Why ItemTemplate will make items disappear for ListView? - wpf

I was solving Windows Phone 8.1 ListView wobbling problem and had code like below, however, once I add the ItemTemplate, the contents of the List cannot be seen, I'm wondering why and how to fix the problem.
<ListView
Grid.Row="1"
x:Name="ListViewEvents"
Loaded="OnListViewEventsLoaded"
ItemsSource="{Binding xx}"
ItemTemplateSelector="{StaticResource xx}"
ItemContainerStyle="{StaticResource xx}"
IsItemClickEnabled="True">
<ListView.ItemTemplate >
<DataTemplate >
<Grid Width="{Binding ActualWidth, ElementName=EventsListGrid}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Your Width binding is trying to read the ActualWidth property of an element in your XAML named EventsListGrid, but there's no such element in the sample code you've provided. As such, the binding engine is unable to set the Width property on your grid, most likely setting it to some unset/NaN value. At least I can confirm this when setting up a similar case as the one you provided and inspecting in Snoop the ListViewItem containers generated for each item in the test collection bound to the ListView. Perhaps you want to set the element name to ListViewEvents in this case or some other parent element not shown in the example?

Related

Difference between preview and running program

Sorry for my bad headline but I couldn't figure out a better one. Heck, I don't even know how to properly ask my question. But here it comes.
I have a custom control in WPF, let's call it Cell. This control does have a few dependency properties, one Text to show in the Cell and a few "decorative" properties for background color, foreground color and so on. If I use this Cell control stand-alone, everything works fine so far.
Then I have another custom control inheriting from ItemsControl, let's call it Field. This control should show a text and some Cells. it has some "decorative" properties for the text part as well. The information about showing Cells is given to the control by a DataTemplate, something like
<DataTemplate x:Key="CellTemplate"
DataType="...">
<ns:Cell Text="{Binding Text}"
Background="{Binding ...}" />
</DataTemplate>
...
<ns:Field ItemsSource="{Binding Cells}"
ItemTemplate="{StaticResource CellTemplate}" />
If I use this Field control stand-alone, everything works fine so far.
Now I want to show several Field controls at once. So I put an ItemsControl on my window and gave an ItemTemplate again, something like:
<DataTemplate x:Key="CellTemplate"
DataType="...">
<ns:Cell Text="{Binding Text}"
Background="{Binding ...}" />
</DataTemplate>
<DataTemplate x:Key="FieldTemplate"
DataType="...">
<ns:Field ItemsSource="{Binding Cells}"
ItemTemplate="{StaticResource CellTemplate}"
FieldText="{Binding Text}"
TextBackground="{Binding ...}" />
</DataTemplate>
<ItemsControl ItemsSource="{Binding Fields}"
ItemTemplate="{StaticResource FieldTemplate}" />
As long as I preview my WPF window everything works fine so far. Changing the values of some "decorative" properties at Cell level or at Field level is immediately shown in the preview.
But if I run my program it seems that all "decorative" properties at Cell level are ignored. I can see all my Fields with their respective texts and I can see every Cell in every Field with their respective texts. But all Cells are plain white. All set colors are not shown.
Snoop tells me, that every color is set to Transparent by the ParentTemplate.
Visual Studio doesn't show me any exceptions or any binding errors. So I'm kind of stuck at where or how I can find the error and fix it.
So I wanted to ask you, if you may have a hint for me.
Does this contruction with a DataTemplate containing a DataTemplate and both DataTemplates bind to it's DataContext work?
Or does it have something to do with maybe re-using Brush objects that shouldn't be re-used?
But why is it working in the preview?

WPF ListBox ListBoxItem Binding

I am going through the Sams book "Teach Yourself WPF in 24 Hours". At one point the authors show how you can bind a ListBox's selected-item value to a property. I get that, it's pretty straightforward. But when I try to create my own ListBox control with my own ListBoxItems, I can't seem to get it to work.
The ListBox that works uses a system collection as its ItemsSource property:
<ListBox x:Name="FontList"
DockPanel.Dock="Left"
ItemsSource="{x:Static Fonts.SystemFontFamilies}"
Width="160" />
The value selected from this ListBox is then used in a TextBlock as follows:
<TextBlock Text="Test"
FontFamily="{Binding ElementName=FontList, Path=SelectedItem}"
TextWrapping="Wrap"
Margin="0 0 0 4" />
Notice that the Path is set to SelectedItem.
Now, I wanted to set the FontSize using another ListBox that contains 3 different sizes. Here is what I did:
<ListBox x:Name="Size" >
<ListBoxItem>10</ListBoxItem>
<ListBoxItem>15</ListBoxItem>
<ListBoxItem>20</ListBoxItem>
</ListBox>
And then I added a binding to the Size attribute of the TextBox as follows:
<TextBlock Text="Test"
FontFamily="{Binding ElementName=FontList, Path=SelectedItem}"
Size="{Binding ElementName=Size, Path=SelectedItem}"
TextWrapping="Wrap"
Margin="0 0 0 4" />
The Size doesn't change when I run the program. So I tried to add the binding I was using for Size to the Text attribute--in order to see its value:
<TextBlock Text="{Binding ElementName=Size, Path=SelectedItem}""
FontFamily="{Binding ElementName=FontList, Path=SelectedItem}"
Size="{Binding ElementName=Size, Path=SelectedItem}"
TextWrapping="Wrap"
Margin="0 0 0 4" />
I see that it is changing as I click the Size ListBox, but I also see that the SelectedItem is displaying as this (when I click the 15 entry):
System.Windows.Controls.ListBoxItem:15
My questions:
1) What is the actual value being returned by the Path called SelectedItem? Is it "System.Windows.Controls.ListBoxItem:15" or is it "15"? If it's not 15, how can I specify a Path that returns just 15 and not System.Windows.Controls.ListBoxItem:15?
2)Why does the FontFamily SelectItem work? I realize that the FontList is coming from a System collection of font names, but it is unclear to me why the ListBox isn't returning a collection of ListBoxItems as text. If my ListBox's Path reference is returning a SelectedItem object of type ListBoxItem, then I would think I could use a Path of SelectedItem.Value or something like that--but it doesn't work and there is no Intellisense to help me.
I want to get THIS example working because it will help clear-up some misunderstandings I have. Please don't refactor the solution to get it to work some other way unless it's entirely impossible for me to have a Path reference that will give me just the numeric portion of my Size ListBoxItem that is selected.
What is the actual value being returned by the Path called SelectedItem?
It is System.Windows.Controls.ListBoxItem:15 (you can read this as "ListBoxItem with content set to 15"), that's why your binding does not work - it expects a numeric value, not ListBoxItem. You can specify Path as SelectedItem.Content to make this work. Also you can set SelectedValuePath of ListBox "Size" to "Content", and bind to SelectedValue property instead of SelectedItem.
Solution 1:
<TextBlock Size="{Binding ElementName=Size, Path=SelectedItem.Content}" />
Solution 2:
<ListBox x:Name="Size" SelectedValuePath="Content" />
<TextBlock Size="{Binding ElementName=Size, Path=SelectedValue}" />
Why does the FontFamily SelectItem work?
Because that ListBox contains a font collection, not a collection of ListBoxItems (they are still created to represent each item in a collection though). You can achieve the same behavior with font sizes if you define collection of font sizes in code and bind ListBox'es ItemsSource property to that collection or define contents of your ListBox as a collection of System.Double values directly in XAML:
<ListBox x:Name="Size"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:Double>10</system:Double>
<system:Double>15</system:Double>
<system:Double>20</system:Double>
</ListBox>
1) The actual value being returned by your SelectedItem binding is a ListBoxItem object. To get the value (15) from your binding you could use a converter or make your binding path a bit more explicit to get the listbox item's Content property value:
Size="{Binding ElementName=Size, Path=SelectedItem.Content}"
2) This is a covariant operation so the type of each list item is inferred from its source. The items generated by your font family items control (ListBox) are a result of the collection it's bound to. The Items property (populated via the ItemsSource dependency property) is an ItemCollection of generic objects which take on the type of their corresponding contextual objects.

DataBinding to a List in silverlight

I've got a Grid which contains a TextBlock. The Grid's DataContext is of type List<MyClass>, and I'd like to bind the TextBlock.Text property to the MyClass.MyProperty property of first element in the List. I tried something like:
<Grid x:Name="RootLayout">
<TextBlock Text="{Binding [0].MyProperty}" />
</Grid>
But of course, that did not work. What's the right way of doing this?
Edit:
I'm going to try and make my explanation more clear. I've got multiple elements in the grid, each of which binds to a different item in the list. The items are laid out in a customized manner which cannot be accomplished by a GridView or ListBox. One of the items in the Grid is the TextBlock, and I'd like to bind its Text property to a property of the first element in the list. Once I know how to do that, I can extend that knowledge to add bindings to the rest of the elements in the grid.
Edit 2:
Turns out, my code works just fine in Silverlight. My project is actually a WinRT project, but I figured I'd get quicker answers if I tagged it as Silverlight, since databinding is supposed to work the same. I'm assuming this is a bug in WinRT, so I'll just have to find a workaround for it :(
I'm not sure I get why you want to do this, but you could create a property that returns what you want from the item in the list like so:
public string MyBindingProperty
{
get { return MyList != null && MyList.Count > 0 ? MyList[0].MyProperty : "Error Text"; }
}
Then you'd bind to MyBindingProperty:
<TextBlock Text="{Binding MyBindingProperty}" />
EDIT
I was wrong in saying you can't get at the items in the List - my bad. Your binding should look like this:
<TextBlock Text="{Binding [0].MyProperty}" />
If you need me I'll be in the corner enjoying my humble pie.
I am not an expert of SL but I think your are using the wrong Grid object; try with DataGrid in this way:
<data:DataGrid x:Name="targetDataGrid">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="MyProperty"
Binding="{Binding MyProperty}" />
</data:DataGrid.Columns>
</data:DataGrid>
also see here for more details: Defining Silverlight DataGrid Columns at Runtime
Edit: then go this way:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding MyProperty}" />
</Grid>
found here: http://msdn.microsoft.com/en-us/library/cc278072%28v=VS.95%29.aspx scroll donw the article...

Binding to container not working, but binding to objects works

I have the following Xaml (Silverlight, but it shouldn't matter):
<ListBox x:Name="Results"> ... </ListBox>
<StackPanel DataContext="{Binding ElementName=Results, Path='SelectedItem.Attributes'}">
<TextBlock Text="{Binding ElementName=Results, Path='SelectedItem.Attributes[ID]'}" />
<TextBlock Text="{Binding '[ID]'}" />
</StackPanel>
When I populate the ListBox, the second TextBlock is populated, but the first TextBlock is not. When I select any Item from the Listbox the first TextBlock is populated, but the second doesn't change.
I'm assuming that I'm missing something to tell the StackPanel's DataContext that it needs to refresh any time I change the SelectedItem in my ListBox, but I'm at a loss on what I need to do.
Ideally, I'd like to not have to bind to the whole path for each of my TextBlocks (there are going to be a bunch of them).
Gaah... I found it. Some nitwit (you read.. me) decided that it'd be smart to override the stackpanel's datacontext when I populated the ListBox. Sorry for anyone that was working on this.

Silverlight 3: Using list of UserControls as ItemsSource for TreeView

I want to populate a TreeView with UserControls, but I only want the Name property to show up, not the entire UserControl. The following code gives me weird crashes as soon as I add something to myUCs:
C#:
var myUCs = new ObservableCollection<UserControl>();
MyTreeView.ItemsSource = myUCs;
XAML:
<controls:TreeView x:Name="MyTreeView">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
Does anyone know how to use a list of UserControls as an ItemSource for TreeViews?
I found one not so convenient workaround: instead of a List of UserControls, use a Dictionary, and change the XAML to:
<controls:TreeView x:Name="MyTreeView">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key.Name}"/>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
The same bug(?) exists in ListBox, a solution is provided here:
Use UIElements as ItemsSource of ListBox in Silverlight
That particular fix does not work for TreeView
You may have to create your own class that extends UserControl and override the ToString() method so that it returns the name property.

Resources