This is my first time building a UWP app and I'm new to c#/Windows in general. I am trying to use a Pivot in the UI. I want the pivot headers to be from an ObservableCollection
of usb devices connected, which go by the class Device_Info
. Each USB Device has a property called HardwareRevNumMajor
that I would like to display as each pivots header. My xaml looks like this:
<Page
x:Class="usb_test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:usb_test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:code="using:usb_test"
mc:Ignorable="d">
<Page.DataContext>
<local:View_Model/>
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot x:Name="pivot1" Title="Pivot" Opacity="0.99" ItemsSource="{Binding Devices}">
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<Binding Path="Device_Info.HardwareRevNumMajor"/>
</TextBlock.Text>
</TextBlock>
<!--<TextBlock Text="{Binding HardwareRevNumMajor}">
</TextBlock>-->
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding DeviceFiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding numBlocks}"/>
<TextBlock Text="{Binding syncTime}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</Grid>
As soon as a Device_Info
object gets added to the Devices
observableCollection I get an error. Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
. Then if I click in my MainPage.xaml file in the designer I see this:
TargetException: Object does not match target type.
StackTrace:
at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj,
BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
InnerException: None
You can see from the xaml above that I've tried a number of ways to display the HarwareRevNumMajor
property that lives on a Device_Info
by the commented out TextBlock
code.
My ViewModel looks like this:
namespace usb_test
{
public class View_Model
{
public ObservableCollection<Device_Info> _devices;
public ObservableCollection<File_Info> _deviceFiles;
public CoreDispatcher _dispatcher;
public View_Model() {
_devices = new ObservableCollection<Device_Info>();
_deviceFiles = new ObservableCollection<File_Info>();
}
public ObservableCollection<Device_Info> Devices
{
get
{
return _devices;
}
}
public ObservableCollection<File_Info> DeviceFiles
{
get
{
return _deviceFiles;
}
}
In My MainPage.xaml.cs I have this:
namespace usb_test
{
public sealed partial class MainPage : Page
{
Device_List devList = new Device_List();
Device_Structure deviceStruct = new Device_Structure();
View_Model viewModel = new View_Model();
public MainPage()
{
this.InitializeComponent();
viewModel._dispatcher = Dispatcher;
this.DataContext = viewModel;
devList.devices.CollectionChanged += this.OnCollectionChanged;
deviceStruct.deviceFiles.CollectionChanged += this.OnCollectionChanged;
...
This line of code is what adds a device to the list:
await viewModel._dispatcher.RunAsync(CoreDispatcherPriority.Normal, async() => { devList.devices.Add(devInfo); });
This line succeeds and adds a Dev_Info
object into the devices observableCollection and shortly after the application crashes.
I'm sure there are more errors when I try to display File Info stuff later in the xaml but I'd really appreciate just getting the pivot header to display correctly. Like I said I'm very new to this so I'm assuming there are a number of problems, I'd appreciate any advice/clarity into what is stopping me from not being able to display a property from a Dev_Info
object.
Thanks!
Your items from Devices
are of type Device_Info
. In your DataTemplate
your bind the text property to Device_Info.HardwareRevNumMajor
. Since the context is your item (Device_Info), you try to access a property Device_Info.
If your write:
<TextBlock Text="{Binding HardwareRevNumMajor}" />
You try to access the property HardwareRevNumMajor
wich probably exists in Device_Info.
Thanks for the suggestions above. I made some progress.
I rewrote my xaml like this:
<Page
x:Class="usb_test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:usb_test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:code="using:usb_test"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot x:Name="pivot1" Title="Pivot" Opacity="0.99" ItemsSource="{x:Bind viewModel.Devices}">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="local:Device_Info">
<TextBlock Text="{x:Bind HardwareRevNumMajor}"></TextBlock>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate x:DataType="local:Device_Info">
<ListView ItemsSource="{x:Bind devStruct.deviceFiles}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:File_Info">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Red" Text="{x:Bind fileName}" HorizontalAlignment="Center" Margin="0,0,20,0"/>
<TextBlock Foreground="Red" Text="{x:Bind numBlocks}" HorizontalAlignment="Center" Margin="0,0,20,0"/>
<Button Content="Download File" Click="{x:Bind onDownloadClick}" HorizontalAlignment="Center" Margin="0,0,20,0">
</Button>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</Grid>
You'll notice I took out the
<Page.DataContext>
<local:View_Model/>
</Page.DataContext>
from my previous xaml code.
Then I used ItemsSource="{x:Bind viewModel.Devices}">
in the Pivot. viewModel
is defined in my MainPage.xaml.cs and is an instance of the View_Model
class I created above. Then from there I added a DataType
to DataTemplate
which is a Device_Info
and then I could easily access an attribute of the Device_Info
object, in this case HardwareRevNumMajor
.
The PivotItemTemplate is a little more confusing. The class Device_Info
has a property on it called devStruct
which is a class I created (Device_Struct
). An instance of Device_Struct
has an ObservableCollection of File_Info
objects. So this collection tells us the files on the device and it's called deviceFiles
. That is the collection I wanted to use inside the Pivot Items. I'm not sure if there's a way to do this without inserting a <ListView>
into the XAML but this is what I found works. With this I can now display information about the files on each Pivot Item.
I also switched from using Binding
to x:Binding
. To be honest I'm not sure exactly why that helped but when I used Binding I was getting: Object reference not set to an instance of an object
. If anyone has a better understanding of that, I'd love to hear about it. Thanks again!
User contributions licensed under CC BY-SA 3.0