XamDataGrid Collection Column - wpf

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>

Related

Performance issue - DataTemplate and DataBinding - 1st load

Here a drawing of my UI:
I have a list of elements at the top (clickme1 and clickme2). Each of this element will have several information contained inside MyList that I want to display inside the customElement of the listbox.
Clickme1 is clicked by default. When I click on the Clickme2, the listbox is taking 2-3 seconds before updating the CustomElements by the information of the Clickme2. When I switch again, it's updating right away so the problem is visible only for the first click. CustomElement has a lot of different bindings to the Clickme element (images and texts).
Here my code:
public ObservableCollection<CustomClass> MyList { get; set; }
<ListBox x:Name="MyListBox"
ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible"
ItemsSource="{Binding MyList}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:CustomElement x:Name="MyCustomElement"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Border" BorderBrush="Transparent" Background="Black">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I tried to use the VirtualizingStackPanel instead of the WrapPanel but it did not improve anything.
Any help ?
When you repopulate the collection, are you assigning a new ObservableCollection? Or working on the existing one?
You should populate your collection "off-line" and then bind it. Or Google for an ObservableCollection derivative that supports "bulk insert". The standard ObservableCollection will send a UI update for every insert.
WRONG:
MyList.Clear();
MyList.Add(...);
RIGHT:
ObservableCollection<CustomClass> coll = new ...
coll.Add(...);
MyList = coll;

items are not displayed after grouping in ItemsControl

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}}" ...

How to access a child control's property when it is declared in a ControlTemplate?

I have a GridView in which I want to embed a checkbox into the header of one of the columns. I need to check it's IsChecked property in code-behind. However, I cannot access it by name as it is in a template for the column header like below:
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.HeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}" >
<Border Background="SkyBlue" BorderBrush="Black" BorderThickness="1,1,0,1">
<CheckBox Name="_cbAllSettingFiles"
Command="{Binding Path=CheckAllLocationFilters}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GridViewColumn.HeaderContainerStyle>
...
Is there another way to access the value of the IsChecked property in code-behind? Or am I going about this the wrong way in the first place?
You'll want to bind it to some property, it's far easier to access that way.

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.

Resources