binding in datagrid group header - wpf

I would like to see in the group header of a datagrid some additional information per column. The header consists of a Stackpanel with some sub Stackpanels in it.
Due to the fact that the user can adjust the size of the columns of the datagrid I have to adjust the size of the single header parts per binding the width of them to the width of the corresponding column:
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="False">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<StackPanel
Orientation="Horizontal"
Width="{Binding Source={x:Reference TextCol01}, Path=ActualWidth}" >
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Path=ItemCount}" FontSize="13" FontWeight="Bold"/>
<TextBlock Text=")"/>
</StackPanel>
<StackPanel
Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Path=ItemCount}" FontSize="13" FontWeight="Bold"/>
<TextBlock Text=")"/>
</StackPanel>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
Without binding the Width (Width="{Binding Source={x:Reference TextCol01}, Path=ActualWidth}") the binding to the Name and the ItemCount of the CollectionViewGroup works perfect. But with binding the Width it fails.
I suppose it is to do with Binding Source. That changes the context or so. But I don't know what exactly is wrong with it.
Could anyone help? Thank you!

I figured it out. This way to bind the width is working well:
Width="{Binding ElementName=TextCol01, Path=ActualWidth}"
this doesn't work:
Width="{Binding Source={x:Reference TextCol01}, Path=ActualWidth}"
It works standalone but together with the bindings of ItemCount and Name it leads to a failure.

Related

Orientating elements in a TreeView

I have a TreeView in my XAML, each element of which is a StackPanel which allows each element to have an image and some text. They are orientated one atop the other as you can see here.
What I would like, and this may not be possible with a TreeView, is for the items (in this case 'FamilyMember') to appear horizontally rather than vertically. So, for example, you click the drop down for the family - you don't see them in a vertical list but in a horizontal one.
The XAML is as follows:
<TreeView Name="trvFamilies">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type self:Family}" ItemsSource="{Binding Members}">
<StackPanel Orientation="Horizontal">
<Image Source="{StaticResource ImageGroup}" Margin="0,0,5,0" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" [" Foreground="Blue" />
<TextBlock Text="{Binding Members.Count}" Foreground="Blue" />
<TextBlock Text="]" Foreground="Blue" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type self:FamilyMember}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" (" Foreground="Green" />
<TextBlock Text="{Binding Age}" Foreground="Green" />
<TextBlock Text=" years)" Foreground="Green" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
Any attempts made within the DataTemplate element only apply to each of the vertically aligned elements.
Maybe my efforts are on the wrong track if this is my goal. If so, if an alternative panel or control is better than I will gladly use it.
Thanks!

GridViewColumn header alignemenet

I have a GridView:
<GridViewColumn Width="{Binding ElementName=helperField, Path=ActualWidth}" >
<GridViewColumn.Header>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{x:Static lang:TextResource.name}" HorizontalAlignment="Left" Width="200" />
<TextBlock Margin="20,0,0,0" Text="{Binding SelectedWorkingDate.WorkingDate.Date, StringFormat=d}" Width="100" />
<TextBlock Margin="0,0,17,0" Text="{x:Static lang:TextResource.workingtime_time}" Width="80" />
<TextBlock Text="{x:Static lang:TextResource.desc}" Margin="15,0,0,0" Width="300" HorizontalAlignment="Right" />
</StackPanel>
</GridViewColumn.Header>
...
Now my gridViewColumn filling all the available space, but the header also is moving after f.e. maximizing the window.
What can I do to have explicit position of my StackPanel in the header.
I have also created a blank project with ListView, set the GridViewColumn width="900" and see the same behavior, so maybe there is a property I should use to change that behavior?
You can use Canvas:
<Canvas>
<TextBlock Canvas.Top="20" Canvas.Left="20" Text="{x:Static lang:TextResource.name}"
</Canvas>

How can I display an itemsCount for Expander content

I have spent wayyyy too much time on this, so if someone can help point me in the right direction, I would be very appreciative.
I have an Expander with a ListBox in it. I have bound the ListBox to a List ie FilteredProjects. I would like the Header of the expander to reflect the number of items in the displayed list. I did implement INotifyPropertyChanged for ProjectsCount, and the ItemsSource for the ListBox updates just fine. Thanks in advance for your time.
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Projects" />
<Border CornerRadius="4" Padding="0" BorderThickness="1" BorderBrush="Black" Background="#FF545F42" Margin="1,0,0,0" >
<Label Content="{Binding Path=ProjectsCount, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource filter}}" Padding="0" FontSize="8" FontStyle="Italic"></Label>
</Border>
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<ListBox x:Name="ProjectsFilterListView" Opacity="1" ItemsSource="{Binding FilteredProjects}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding ItemName}" Margin="10,10,0,10"></CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
You could just get the Item Count directly from the ListBox
<Label Content="{Binding Path=Items.Count, ElementName=ProjectsFilterListView}" />
Here is an example of it working, I replaced Label for TextBlock so I could use StringFormat to add "Items:" text before the number as I am not sure what your Converter is doing
<StackPanel Orientation="Horizontal">
<TextBlock Text="Projects" />
<Border CornerRadius="4" Padding="0" BorderThickness="1" BorderBrush="Black" Background="Red" Margin="1,0,0,0" >
<TextBlock Text="{Binding Path=Items.Count, ElementName=ProjectsFilterListView, StringFormat={} Items: {0}}" Padding="0" FontSize="10" FontStyle="Italic" Foreground="Black"/>
</Border>
</StackPanel>
Result:

How can I make a ListBox expand to fit the entire available width?

I need to make the ListBox expand to fit the width it has available. Here's the XAML:
<ListBox Grid.Row="2" Height="400" ItemsSource="{StaticResource Notes}" VerticalAlignment="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Height="90" Margin="5">
<TextBlock Text="{Binding Title}" FontSize="30" />
<TextBlock Text="{Binding Text}" FontSize="15" />
<Rectangle Fill="#1192D4" Height="2" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Please take a look at this post
A ListBoxItem that fills its parent

How to combine my seemingly redundant XAML

I have 8 different XAML DataTemplates that are all very similar. Here are 2 of them:
<DataTemplate x:Key="ConflictFieldStringCellContentTemplate">
<StackPanel>
<TextBlock Text="{Binding ClientVersion.Value}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}" />
<Label Background="LightGray" Height="1" Margin="0, 4, -4, 2"></Label>
<TextBlock Text="{Binding ServerVersion.Value}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ConflictFieldStringArrayCellContentTemplate">
<StackPanel>
<TextBlock Text="{Binding ClientVersion.Value, Converter={StaticResource stringArrayToCommaDelimitedStringConverter}}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}"/>
<Label Background="LightGray" Height="1" Margin="0, 4, -4, 2"></Label>
<TextBlock Text="{Binding ServerVersion.Value, Converter={StaticResource stringArrayToCommaDelimitedStringConverter}}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}"/>
</StackPanel>
</DataTemplate>
As you can see, the only difference is that they use a different Converter for the Binding of the Text property of the TextBlock. Is there any way for me to factor out the commonalities of these two DataTemplates? I have 6 more and updating them is getting very tedious, because everything is identical except for the Converter for the Binding of the Text property.
Is there a way to somehow factor this out into one template which can be parameterized somehow? Something like this would be cool (pseudo-code):
<DataTemplate x:Key="BaseCellContentTemplate">
<StackPanel>
<TextBlock Text="{??}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}" />
<Label Background="LightGray" Height="1" Margin="0, 4, -4, 2"></Label>
<TextBlock Text="{Binding ServerVersion.Value}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ConflictFieldStringCellContentTemplate" BaseTemplate="BaseCellContentTemplate">
<??>{Binding ClientVersion.Value}</??>
</DataTemplate>
<DataTemplate x:Key="ConflictFieldStringArrayCellContentTemplate" BaseTemplate="BaseCellContentTemplate">
<??>{Binding ClientVersion.Value, Converter={StaticResource stringArrayToCommaDelimitedStringConverter}}</??>
</DataTemplate>
If there is only one value, and you want to do it purely with templates, you might do:
<DataTemplate x:Key="VersionDisplayTemplate">
<StackPanel>
<TextBlock Text="{TemplateBinding Tag}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}" />
<Label Background="LightGray" Height="1" Margin="0, 4, -4, 2"></Label>
<TextBlock Text="{TemplateBinding Content}"
Foreground="{Binding Path=Mismatch, Converter={StaticResource mismatchBoolToBrushConverter}}"/>
</StackPanel>
</DataTemplate>
Now you can use it as:
<DataTemplate x:Key="ConflictFieldStringCellContentTemplate">
<ContentPresenter
Tag="ABC"
Content="{Binding ClientVersion.Value}"
ContentTemplate="{StaticResource VersionDisplayTemplate}"
/>
</DataTemplate>
<DataTemplate x:Key="ConflictFieldStringArrayCellContentTemplate">
<ContentPresenter
Tag="XYZ"
Content="{Binding ClientVersion.Value, Converter={StaticResource stringArrayToCommaDelimitedStringConverter}}"
ContentTemplate="{StaticResource VersionDisplayTemplate}"
/>
</DataTemplate>
One path you can try is to create a new User Control.
This User Control should contain the StackPanel, and this StackPanel should contain the TextBox, Label and TextBox.
You could implement the TextConverters as dependency properties.
The final set of DataTemplates would look like this:
<DataTemplate x:Key="ConflictFieldStringCellContentTemplate">
<local:VersionDisplayControl
ClientVersionTextConverter="{StaticResource stringArrayToCommaDelimitedStringConverter}" />
</DataTemplate>
<DataTemplate x:Key="ConflictFieldStringArrayCellContentTemplate">
<local:VersionDisplayControl
ClientVersionTextConverter="{StaticResource stringArrayToCommaDelimitedStringConverter}"
ServerVersionTextConverter="{StaticResource stringArrayToCommaDelimitedStringConverter}" />
</DataTemplate>
This is assuming that the User Control is able to access the source version information from some globally available source.
If not, the VersionDisplayControl will have to expose another public property, probably called VersionSource.

Resources