items are not displayed after grouping in ItemsControl - wpf

I've added grouping to ItemsControl:
<ItemsControl Style="{StaticResource SellingDashboardToDosList}" Grid.Row="2" BorderThickness="1" Background="#C7E8F8" HorizontalAlignment="Stretch" ItemsSource="{Binding ToDoList}" >
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<GroupBox Header="{Binding Name}">
<ItemsPresenter />
</GroupBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ItemsControl.GroupStyle>
</ItemsControl>
Now I see only empty GroupBoxes. I've used Snoop tool to explore the application and I found out that GroupBox ItemPresenters are empty! What could be the reason of it?
If I remove the grouping from the ItemsControl (the ItemsControl.GroupStyle element), then everything works fine, and I see all items again. I don't need to make any changes to the underlying data context to see all items. The data context (the ItemsSource binging) is of type CollectionViewSource.
The binding tracing is turned on, but I don't see any binding errors.

It appears that ItemsControl style was overriding ItemsControl.Template property. The problem was solved once that style got overridden.

You have to group your data first. Use CollectionViewSource to do that:
<CollectionViewSource x:Key="Data" Source="{StaticResource SellingDashboardToDosList}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="PropertyNameToGroupBy"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
And only then you can do the following:
<ItemsControl ItemsSource="{Biding Source={StaticResource Data}}" ...

Related

XAML: UniformGrid where you can define cells as not unifrom in size?

As a part of an ItemsControl style I'd like to have something that works similar ot Grid/UniformGrid as an ItemsPanel.
In its simplest form, the Style would look like this:
<Style TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="2" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Margin" Value="10"/>
</Style>
</Setter.Value>
</Setter>
</Style>
and I would use it like this:
<WrapPanel Orientation="Vertical">
<ItemsControl>
<TextBlock Text="Label1:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label2:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label3:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label4:"/>
<TextBlock Text="ThisWillBeBoundButIsSomewhatLongerThenTheOtherProperties" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label5:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label6:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
</WrapPanel>
As you can see, you would throw a Label for a property into this plus a binding to that property and they would stick together even if things would wrap around becuase of different sizes of the app window for example.
The nice thing here about theUniformGrid is that it seems that if one Label is longer the others will get the same space meaning the bound properties would line up neatly (why this happens I don't understand because these should be seperate UniformGrids I guess). Problem here is that the cell width of the Label part and the Property part is the same, so if the property is long there will be a large gap between the Label and the Property.
Using normal Grid instead would mean I'd have to set the Grid.Column="0" and Grid.Column="1" everyplace I put items into this ItemsControl. That's not really what I wan't.
Is there a way for me to have some sort of grid that lines up like the uniform one but doesn't stratch all columns when one only needs to be and assumes you are putting into columns the same way you declare the items?
The way I've typically seen this sort of scenario handled is via a combination of Grid+IsSharedSizeScope+ListView+DataTemplate.
In this case, the label text (i.e. "Label1:") and entry text (i.e. "ThisWillBeBound") would be in a single item type and a collection of that type of item would be bound to the list view. The Grid.IsSharedSizeScope allows for sharing column size info between different entries while using a template - very handy.
There's a great example of this at http://www.wpftutorial.net/DataTemplates.html. Is this the sort of scenario you're looking for?

What is the type of elements inside an ItemsControl?

When I use a ListBox - the elements inside are of type ListBoxItem, for ComboBox they are ComboBoxItems. What type are they for an ItemsControl? I've been digging through Blend's templates to no avail.
I wish to create a new ControlTemplate for the items inside the ItemsControl.
To clarify with code:
EDIT: Figured out the type as shown below:
<UserControl.Resources>
<Style x:Key="TemplateStyle" TargetType="{x:Type ContentControl}"> <!-- Here I need the correct Type in the TargetType-tag -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}"> <!-- Again, I need the correct Type in a TargetType-tag -->
<DockPanel>
<TextBlock Text="Header" DockPanel.Dock="Top"/>
<ContentPresenter/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</UserControl.Resources>
<ItemsControl ItemContainerStyle="{StaticResource TemplateStyle}"/>
It's simply a ContentPresenter, which implies it will be rendered with whatever DataTemplate is associated with the type.
If you want to take explicit control over how the items are rendered, you can just use ItemTemplate:
<ItemsControl ItemsSource="{Binding Customers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I figured it out by trial and error. The type inside the ItemsControl is some kind of ContentControl (probably just a ContentControl). I'll update the question for others.

XamDataGrid Collection Column

Is there a way to bind to a collection column in a XamDataGrid DataSource?
What i am trying to do is to show all the items of the specific column collection in a single grid field. (using the appropriate templates).
Hope it makes sense to you all. Let me know if you need me to clarify things a little bit more.
I finally found the answer.
I just used a Wrapper class to host the collection and bind to the column to the Wrapper class property instead of the collection property.
After that, making the appropriate template is very easy.
Here is an example:
<Style x:Key="ValidationsStyle" TargetType="{x:Type igDP:CellValuePresenter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type igDP:CellValuePresenter}">
<ContentControl DataContext="{TemplateBinding Value}">
<ItemsControl ItemsSource="{Binding Validations}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ValidationName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ContentControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

How to use Canvas as the ItemsPanel for an ItemsControl in Silverlight 3

I am trying to set the Canvas properties in an ItemsControl DataTemplate with Silverlight 3. According to this post, the only way of doing that is to set it using the ItemsContainerStyle for the ContentPresenter type, since the Canvas properties only take effect on direct children of the Canvas. This doesn't seem to work in SL3, since the ItemsControl doesn't have an ItemsContainerStyle property, so I tried a ListBox as advised by this article, but it still doesn't work. From the XAML below, I would expect to see a green square, with the numbers 10, 30, 50, 70 cascading from "NW" to "SE" direction. Can anyone tell me why they are all stacked on top of eachother in the NW corner?
<UserControl x:Class="TestControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib" >
<StackPanel>
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Green" Width="100" Height="100" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding}" />
<Setter Property="Canvas.Top" Value="{Binding}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Items>
<System:Int32>10</System:Int32>
<System:Int32>30</System:Int32>
<System:Int32>50</System:Int32>
<System:Int32>70</System:Int32>
</ListBox.Items>
</ListBox>
</StackPanel>
</UserControl>
I'm not sure if it will work in your scenario, but I've accomplished this in the past using the RenderTransform.
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Green" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}">
<TextBox.RenderTransform>
<TranslateTransform X="100" Y="100" />
</TextBox.RenderTransform>
</TextBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Items>
<System:Int32>10</System:Int32>
<System:Int32>30</System:Int32>
<System:Int32>50</System:Int32>
<System:Int32>70</System:Int32>
</ItemsControl.Items>
</ItemsControl>
Or in the case of binding you will need to use a converter
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Green" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" RenderTransform="{Binding Converter={StaticResource NumberToTransformGroupConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Items>
<System:Int32>10</System:Int32>
<System:Int32>30</System:Int32>
<System:Int32>50</System:Int32>
<System:Int32>70</System:Int32>
</ItemsControl.Items>
</ItemsControl>
Converter
public void ConvertTo(object value, ...)
{
int intValue = int.Parse(value.ToString());
return new TransformGroup()
{
Children = new TransformCollection()
{
new TranslateTransform { X = intValue, Y = intValue }
}
};
}
Silverlight4 does not bind to attached properties in style. I suggest using David Anson's approach described here.
<UserControl.Resources>
<Style x:Key="ScreenBindStyle" TargetType="ListBoxItem">
<Setter Property="Helpers:SetterValueBindingHelper.PropertyBinding">
<Setter.Value>
<Helpers:SetterValueBindingHelper>
<Helpers:SetterValueBindingHelper Type="Canvas" Property="Left" Binding="{Binding LocationField.Value.X}" />
<Helpers:SetterValueBindingHelper Type="Canvas" Property="Top" Binding="{Binding LocationField.Value.Y}" />
<Helpers:SetterValueBindingHelper Type="Canvas" Property="ZIndex" Binding="{Binding ZIndex.Value}" />
</Helpers:SetterValueBindingHelper>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
And in listbox:
ItemContainerStyle="{StaticResource ScreenBindStyle}"
Old post but I went into the same problem but now with SL5 that now allows Binding in style setters. I was trying to avoid to use the ListBox (because it handles selection and so on) and the ItemsControl still doesn't have an ItemContainerStyle. So I tried a few things.
I haven't found many subject discussing this problem so let me share my solution (sorry if it duplicates)
In fact, I found a very convenient way to solve the problem by adding an unnamed Style in the ItemsControl resources :
<ItemsControl ItemsSource="{Binding Path=MyData}">
<ItemsControl.Resources>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="{Binding Path=Bounds.Top}"/>
<Setter Property="Canvas.Left" Value="{Binding Path=Bounds.Left}"/>
<Setter Property="Width" Value="{Binding Path=Bounds.Width}"/>
<Setter Property="Height" Value="{Binding Path=Bounds.Height}"/>
</Style>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="my:DataType">
...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Works like a charm in SL5 :)
I can't explain what you are seeing either. Your Xaml is broken in at least a couple of ways.
First the Xaml itself fails because this:-
<Style TargetType="ContentPresenter">
should be
<Style TargetType="ContentControl">
the Item Containers in the case of ListBox are of type ListBoxItem which derive from ContentControl.
Still without that the placing {Binding} in style setters still doesn't work. I guess you were imagining that the style would be applied to each item in turn and get its Value from the current item. However even if binding worked in the style, there would only be one style and it would get its data binding from the ListBox DataContext. This is a different DataContext that applies to each ListBox item (which in this case is each Item in the Items collection).
Still I think Ben has a reasonable solution in place which eliminates this approach.

ZOrder of Expander with Canvas inside of List

I have a list which contains some controls, including an Expander. Within the expander is another list, which I want to overlay the outer list. Here's a simple repro:
<Page.Resources>
<x:Array x:Key="array1" Type="sys:String">
<sys:String>item 1</sys:String>
<sys:String>item 2</sys:String>
<sys:String>item 3</sys:String>
</x:Array>
<DataTemplate x:Key="buttonTemplate">
<Button Content="{Binding}"/>
</DataTemplate>
<DataTemplate x:Key="expanderItem">
<StackPanel>
<Expander Header="Options">
<Canvas>
<StackPanel Panel.ZIndex="999" Background="Red">
<Label>A1</Label>
<Label>A2</Label>
<Label>A3</Label>
<Label>A4</Label>
</StackPanel>
</Canvas>
</Expander>
<Label BorderBrush="Black" BorderThickness="2" Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<ListBox ItemsSource="{StaticResource array1}" ItemTemplate="{StaticResource expanderItem}"/>
</Grid>
When the Expander gets opened, the inner labels get rendered at the same level as the label in the same DataTemplate and the contents later items in the list. I have tried moving the Panel.ZIndex up to the panel with no change.
If I add the following style:
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter Property="Panel.ZIndex" Value="999"/>
</Trigger>
</Style.Triggers>
</Style>
It will properly overlay items in the SAME list item, but still renders intermixed with contents from later list items.
(I suspect this is a fairly obvious layout problem, but I have not been able to find it.)
You could try writing a converter that sets the ZIndex in the datatemplate based on the index of the item in the list. The interesting thing with this would be making sure everything updates correctly as items are added / removed.
Do you need the expander to be independent of layout?

Resources