TextWrapping textbox in WPF DataGrid - c#

I've been trying to make my textboxes in my DataGrid wrap. I got it working but it seems to break the Text binding.
XAML
<DataGrid x:Name="dataGrid" Grid.Row="0" AutoGenerateColumns="False" ItemsSource="{Binding}">
<!-- <DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBox TextWrapping="Wrap" Text="{Binding Path=Value}">
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle> -->
</DataGrid>
I add the columns and rows using a data set like so.
CS
#region Variables
private DataTable m_stringData = new DataTable();
private DataSet m_stringDataSet = new DataSet();
#endregion
#region Constructors
public LocEditor()
{
InitializeComponent();
AddColumn("ID", 100);
AddString("Test");
dataGrid.DataContext = m_stringData;
}
#endregion
#region Methods
private void AddColumn(string l_columnName, int l_iWidth)
{
m_stringData.Columns.Add(l_columnName, typeof(string));
dataGrid.Columns.Add(new DataGridTextColumn
{
Header = l_columnName,
Width = l_iWidth,
Binding = new Binding(l_columnName)
//Binding = new Binding(string.Format("[{0}]", l_columnName))
});
}
private void AddString(string l_stringID)
{
m_stringData.Rows.Add();
m_stringData.Rows[m_stringData.Rows.Count - 1][0] = l_stringID;
}
#endregion
Any help would be greatly appreciated.

Figured it out. By setting the Element and EditingElementStyle, I don't have to reset the Binding.
DataGridTextColumn l_column = new DataGridTextColumn();
l_column.Header = l_columnName;
l_column.Binding = new Binding(l_columnName);
l_column.Width = l_iWidth;
Style l_textStyle = new Style(typeof(TextBlock));
l_textStyle.Setters.Add(new Setter(TextBlock.TextWrappingProperty, TextWrapping.Wrap));
l_column.ElementStyle = l_textStyle;
Style l_textEditStyle = new Style(typeof(TextBox));
l_textEditStyle.Setters.Add(new Setter(TextBox.TextWrappingProperty, TextWrapping.Wrap));
l_column.EditingElementStyle = l_textEditStyle;
dataGrid.Columns.Add(l_column);

This inserts the GridViewColumn directly into the GridView, but it worked for me.
<ListView Name="myListView">
<ListView.View>
<GridView>
<GridViewColumn Header="HEADER NAME" x:Name="header">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox TextWrapping="Wrap" Text="{Binding Path=Value}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
In order to see the wrapped text fully, you will need to set the height of the rows to be large enough to see this (or do height conversions dynamically).
<My:ToHeightConverter x:Key="heightConverter" />
<Style TargetType="ListViewItem">
<Setter Property="Height" Value="{Binding ElementName=myListView, Path=ActualHeight, Converter={StaticResource heightConverter}}" />
</Style>
And then in the code behind the GridView:
[ValueConversion(typeof(double), typeof(double))]
public class ToHeightConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return (((double)value * 10); //return the height wanted here
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}

If you're looking to just add TextWrapping to all TextBoxes in your DataGrid, I would suggest making an implicit style for them in your DataGrid.Resources
<DataGrid.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</DataGrid.Resources>
The reason why the data isn't showing up in your Template is because you're missing the ContentPresenter. This is the object that displays the rendered content of the actual DataGridCell. The DataGridCell itself has no idea what the content of its cell is, so doesn't know what the binding is.
For example, this works
<Style TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBlock TextWrapping="Wrap">
<ContentPresenter Content="{TemplateBinding Content}" />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But not this
<Style TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBox TextWrapping="Wrap" Text="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
because the Content is whatever object happens to be in the cell at the time, whether it is a TextBox, TextBlock, ComboBox, etc

Related

Attached property not working

I am using DevExpress control TreeListControl to display data. This control has columns, like datagrid. I want to show values in the center of the cell. For that I'm using CellTemplate:
<dxg:TreeListColumn HorizontalHeaderContentAlignment="Center" Header="January">
<dxg:TreeListColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding RowData.Row.January}" TextAlignment="Center"/>
</DataTemplate>
</dxg:TreeListColumn.CellTemplate>
</dxg:TreeListColumn>
But I have a lot of columns, and the only difference is value to display. So I decided to use a style and pass value with attached property. Style:
<Style x:Key="TreeListColumnStyle" TargetType="{x:Type dxg:TreeListColumn}">
<Setter Property="HorizontalHeaderContentAlignment" Value="Center"/>
<Setter Property="CellTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{TemplateBinding ap:BenDatagridValueProperty.DataGridValue}" TextAlignment="Center"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
And here is my AttachedProperty:
public static class BenDatagridValueProperty
{
public static readonly System.Windows.DependencyProperty DataGridValueProperty = System.Windows.DependencyProperty.RegisterAttached(
"DataGridValue",
typeof(string),
typeof(BenDatagridValueProperty),
new System.Windows.FrameworkPropertyMetadata("", System.Windows.FrameworkPropertyMetadataOptions.Inherits));
public static string GetDataGridValue(System.Windows.DependencyObject obj)
{
return (string)obj.GetValue(DataGridValueProperty);
}
public static void SetDataGridValue(System.Windows.DependencyObject obj, string value)
{
obj.SetValue(DataGridValueProperty, value);
}
}
Remade column now looks like:
<dxg:TreeListColumn Header="January" Style="{StaticResource TreeListColumnStyle}" ap:BenDatagridValueProperty.DataGridValue="15">
15 is just a test value. And it does not sets value in datagrid columns to 15 (it does not call method SetDataGridValue(DependencyObject obj, string value). If I will write a default value in AttachedProperty, then I can see default value in cells.
Not sure where is error.
Try modify TreeListColumnStyle:
<Style x:Key="TreeListColumnStyle" TargetType="{x:Type dxg:TreeListColumn}">
<Setter Property="HorizontalHeaderContentAlignment" Value="Center"/>
<Setter Property="CellTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock ap:BenDatagridValueProperty.DataGridValue="{TemplateBinding ap:BenDatagridValueProperty.DataGridValue}" Text="{Binding Path=(ap:BenDatagridValueProperty.DataGridValue), RelativeSource={RelativeSource Self}}" TextAlignment="Center"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

Binding a command to a checkbox for onclick inside a xamdatagrid in wpf not working

I have a checkbox inside my XamDataGrid , as follows :-
<igDp:UnboundField Width="1*" Label="{LocText props:Resources.GROUPLIST_SYNC}" BindingMode="TwoWay" BindingPath="IsSynchronise.Value" Converter="{StaticResource BoolToUMDirectoryFilter}" ConverterParameter="Enabled" ToolTip="{LocText props:Resources.GROUPLIST_SYNC}">
<igDp:UnboundField.Settings>
<igDp:FieldSettings AllowEdit="True">
<igDp:FieldSettings.LabelPresenterStyle >
<Style TargetType="igDp:LabelPresenter" BasedOn="{StaticResource GmsLabelStyle }">
<Setter Property="AutomationProperties.AutomationId" Value="Group_SYNC"></Setter>
</Style>
</igDp:FieldSettings.LabelPresenterStyle>
<igDp:FieldSettings.CellValuePresenterStyle>
<Style TargetType="{x:Type igDp:CellValuePresenter}">
<Setter Property="Margin" Value="2"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="igDp:CellValuePresenter">
<CheckBox Name="chkSynchronise" IsChecked="{Binding Path=DataContext.DataItem.IsSynchronise.Value, RelativeSource={ RelativeSource Mode=TemplatedParent}}"
HorizontalAlignment="Center" Command="{Binding SynchroniseGroups,RelativeSource={RelativeSource Mode=Self}}" HorizontalContentAlignment="Left" >
</CheckBox>
<!--<CheckBox IsChecked="{Binding Path=DataContext.DataItem.IsSynchronise.Value, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, RelativeSource={ RelativeSource Mode=TemplatedParent}}"
Command="{Binding SynchroniseGroups,RelativeSource={RelativeSource Mode=Self}}"
HorizontalAlignment="Center" HorizontalContentAlignment="Left" >
</CheckBox>-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</igDp:FieldSettings.CellValuePresenterStyle>
</igDp:FieldSettings>
</igDp:UnboundField.Settings>
</igDp:UnboundField>
So, how should I bind a command to checkbox in order to work it with click and get the behaviour of checked and unchecked inside my ViewModel? Any help would be much appreciated. Thanks in advance.
At first I want to add a side note: Since infragistics release 14.2 the unbound field is obsolete (look here).
For binding a boolean to the XamDataGrid I prefer using a CheckBoxField.
Class:
public class YourClass : NotificationObject
{
private bool _checkBoxValue;
public bool CheckboxValue
{
get
{
return this._checkBoxValue;
}
set
{
if (this._checkBoxValue != value)
{
this._checkBoxValue = value;
// Do something: Event, Method, ...
this.RaisePropertyChanged(nameof(this.CheckboxValue));
}
}
}
}
XAML:
<igDp:FieldLayout>
<igDp:CheckBoxField BindingType="UseAlternateBinding"
Name="CheckerField"
Label="YourCheckerFieldLabel"
ToolTip="YourTooltip"
AlternateBinding="{Binding CheckboxValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
</igDp:FieldLayout>

Binding from Style to Control which applied the Style

I want to create the TextBox that has the Text-hint to describe TextBox value.
for this purpose I use VisualBrush that has TextBlock shows the TextBox hint when the TextBox is empty , then i coded the converter to convert HorizontalContentAlignment of TextBox(control that applied the style) To AlignmentX means that when objective TextBox e.g is left then the visualBrush shows left Alignment TextBlock but this pupose not came true.
how I can fix this like bellow:
My XAML Code:
<Window.Resources>
<local:HorizontalAlignToAlignX x:Key="HAligToXAlig"/>
<Style TargetType="{x:Type TextBox}" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Style.Resources>
<VisualBrush x:Key="CueBannerBrush"
Stretch="None"
AlignmentX="{Binding HorizontalContentAlignment, Converter={StaticResource HAligToXAlig}}">
<VisualBrush.Visual>
<TextBlock Text="search" Foreground="LightGray"/>
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBox x:Name="textBox"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="342"
HorizontalContentAlignment="Right" />
</Grid>
My Converter Code:
class HorizontalAlignToAlignX : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
AlignmentX Align = AlignmentX.Right;
switch ((HorizontalAlignment)value)
{
case HorizontalAlignment.Left:
Align = AlignmentX.Left;
break;
case HorizontalAlignment.Center:
Align = AlignmentX.Center;
break;
case HorizontalAlignment.Right:
Align = AlignmentX.Right;
break;
case HorizontalAlignment.Stretch:
Align = AlignmentX.Center;
break;
default:
break;
}
return Align;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I fund my answer by RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}} like bellow:
<Window.Resources>
<local:HorizontalAlignToAlignX x:Key="HAligToXAlig" />
<Style TargetType="{x:Type TextBox}"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Style.Resources>
<VisualBrush x:Key="CueBannerBrush"
Stretch="None"
AlignmentX="{Binding ConverterParameter=HorizontalContentAlignment, Converter={StaticResource HAligToXAlig}, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=HorizontalContentAlignment}">
<VisualBrush.Visual>
<TextBlock Text="search"
Foreground="LightGray"
TextAlignment="Right" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text"
Value="{x:Static sys:String.Empty}">
<Setter Property="Background"
Value="{StaticResource CueBannerBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBox x:Name="textBox"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="342"
HorizontalContentAlignment="Right" />
</Grid>

how to change the foreground of the datagrid textblock column using binding

In my application, I have used "DataGrid" to bind set of values dynamically. Also based upon the values binded, I need to change the forecolor of the values binded.
Here is my XAML and C# code
XAML:
<my:DataGridTemplateColumn Header="Priority">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Left" Name="txtPriority" Text="{Binding MessagePriority}" FontWeight="Bold">
<TextBlock.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{Binding ForegroundBrush}" />
</Style>
</TextBlock.Resources>
</TextBlock>
</my:DataGrid.Columns>
</my:DataGrid>
C#:
private SolidColorBrush _foregroundBrush;
public SolidColorBrush ForegroundBrush
{
get
{
return _foregroundBrush;
}
set
{
if (_foregroundBrush != value)
{
_foregroundBrush = value;
RaisePropertyChanged(() => _foregroundBrush);
}
}
}
var color = (Color)ColorConverter.ConvertFromString("#FF00FF");
var brush = new SolidColorBrush(color);
ForegroundBrush = brush;
There are a couple of ways that you can do this. It very much depends on your requirements, so it would have been better if you had explained them better and in more detail. However as you didn't, I can't use your exact details in this example and you will have to adapt it to your project. The first way is to simply use a DataTrigger... this method is good for up to around 8 different value/colour pairs:
<DataGrid ItemsSource="{Binding RadioButtonData}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Label}">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding SomeValue}" Value="Something">
<Setter Property="TextElement.Foreground" Value="LightGreen" />
</DataTrigger>
<DataTrigger Binding="{Binding SomeValue}" Value="Another thing">
<Setter Property="TextElement.Foreground" Value="LightBlue" />
</DataTrigger>
<DataTrigger Binding="{Binding SomeValue}" Value="A different thing">
<Setter Property="TextElement.Foreground" Value="LightPink" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The other method that you can use is to use a Converter class with your Binding. You can find a detailed example of doing this in many online posts... here are a few:
How to set Foreground of DataGrid Column with ValueConverter
Datagrid AutoGenerateColumns="True" forecolor IValueConverter
Hai Everyone,
First of all i thanks to all for see my question and at that time send your answers. Now, i got the answer, i have to use the converter class for convert color to Solidcolorbursh like as below:
ValueConverter.cs
public class ValueConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || !(value is decimal))
return new SolidColorBrush(ForegroundBrush);
var dValue = System.Convert.ToDecimal(value);
if (dValue < 0)
return new SolidColorBrush(ForegroundBrush);
else
return new SolidColorBrush(ForegroundBrush);
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
XMAL:
First we can decalre that class namespace like:
xmlns:convert="clr-namespace:Helper"
<Grid.Resources>
<convert:ValueConverter x:Key="ValueConverter"></convert:ValueConverter>
</Grid.Resources>
<my:DataGridTemplateColumn Header="Priority">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Left" Name="txtPriority" Text="{Binding Priority}" FontWeight="DemiBold" Foreground="{Binding Priority, Converter={StaticResource ValueConverter}}">
</TextBlock>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>

WPF GroupStyle only for Groups with more than 1 item

I am trying to show different Groups in a Listview which contain an expander and a header. However I don't want my SecondLevel Group to show a header if the Group only contains 1 item.
Since this would be quite inconvenient.
My Code:
<Window x:Class="ListViewGrouping.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:listViewGrouping="clr-namespace:ListViewGrouping"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<listViewGrouping:GroupItemStyleSelector x:Key="groupItemStyleSelector"/>
<!-- Style for the first level GroupItem -->
<Style x:Key="FirstLevel" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="3.5,0" Text="{Binding Name}" TextBlock.FontWeight="Bold"/>
<TextBlock Grid.Column="1" Margin="3.5,0" Text="Elements:"/>
<TextBlock Grid.Column="2" Margin="3.5,0" Text="{Binding ItemCount}"/>
</Grid>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Style for the second level GroupItem -->
<Style x:Key="SecondLevel" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" Margin="15,0,0,0">
<Expander.Header>
<TextBlock Text="{Binding Name}" TextBlock.FontWeight="Bold"/>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListView Name="mailView" ItemsSource="{Binding}">
<ListView.GroupStyle>
<GroupStyle ContainerStyleSelector="{StaticResource groupItemStyleSelector}" />
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Subject" DisplayMemberBinding="{Binding Subject}"/>
<GridViewColumn Header="Sender" DisplayMemberBinding="{Binding Sender}"/>
<GridViewColumn Header="Support-ID" DisplayMemberBinding="{Binding Support_ID}"/>
<GridViewColumn Header="Supporter" DisplayMemberBinding="{Binding Supporter}"/>
<GridViewColumn Header="Received" DisplayMemberBinding="{Binding ReceivedDate}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
Code behind:
private void createMailList()
{
_mails.Add(new Mail("LIC", "Lizenz geht nicht", "Xeun", "LIC.2013.01.10.002", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "Alles doof", "Xeun", "CD.2013.01.10.002", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "Re:Alles doof", "Xeun", "CD.2013.01.10.002", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "CD kaputt", "Xeun", "CD.2013.01.10.003", "Xeun", "25.09.2013"));
_mails.Add(new Mail("CD", "Geht nicht", "Xeun", "CD.2013.01.10.001", "Xeun", "25.09.2013"));
_mails.Add(new Mail("LIC", "Kaputt", "Xeun", "LIC.2013.01.10.001", "Xeun", "25.09.2013"));
}
public MainWindow()
{
InitializeComponent();
createMailList();
DataContext = _mails;
ICollectionView view = CollectionViewSource.GetDefaultView(_mails);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("ID");
view.GroupDescriptions.Add(groupDescription);
view.GroupDescriptions.Add(new PropertyGroupDescription("Support_ID"));
}
}
public class GroupItemStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
Style s;
CollectionViewGroup group = item as CollectionViewGroup;
Window window = Application.Current.MainWindow;
if (!group.IsBottomLevel)
{
s = window.FindResource("FirstLevel") as Style;
}
else
{
s = window.FindResource("SecondLevel") as Style;
}
return s;
}
}
I hope I explained my problem well enough - I have attached a screenshot of the small app - the Groups marked as red only contain one item and should not be shown as group.
For both styles split the ControlTemplate in 2, one with an expander and one with out.
Create a converter which checks the if the group size (your group is of type CollectionViewGroup)
return yourGroup.Items.Count > 1
Place a DataTrigger as seen below in each style which checks the groups size via the converter
(your DataContext is your group so the binding is Binding="{Binding}"
xaml :
<ControlTemplate TargetType="{x:Type GroupItem}" x:Key="withExpander">
<Expander IsExpanded="True">
<Expander.Header>
.....
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
<ControlTemplate TargetType="{x:Type GroupItem}" x:Key="withOutExpander">
<ItemsPresenter />
</ControlTemplate>
<Style x:Key="FirstLevel" TargetType="{x:Type GroupItem}">
<Setter Property="Template" Value="{StaticResource withExpander}" />
<Style.Triggers>
<DataTrigger Binding="{Binding , Converter={StaticResource GroupSizeToExpanderConverter}" Value="False">
<Setter Property="Template" Value="{StaticResource withOutExpander}"/>
</DataTrigger>
</Style.Triggers>
</Style>
Edit :
*the converter value will be the Group itself (of type CollectionViewGroup)
The Converter :
public class GroupSizeToExpanderConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
CollectionViewGroup grp = (CollectionViewGroup)value;
return grp.Items.Count() > 1; // ALTERNATIVLY grp.ItemCount;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
here is my solution
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Expander IsExpanded="True">
<Expander.Style>
<Style TargetType="Expander">
<Setter Property="Visibility" Value="Visible"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ItemCount}" Value="1">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
<TextBlock Text="{Binding ItemCount}" FontSize="22" Foreground="Green" FontWeight="Bold" FontStyle="Italic" Margin="10,0,0,0" VerticalAlignment="Bottom" />
<TextBlock Text=" item(s)" FontSize="22" Foreground="Silver" FontStyle="Italic" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<Border BorderBrush="LightBlue" BorderThickness="2" Margin="0 2">
<ItemsPresenter />
</Border>
</Expander>
<ItemsPresenter>
<ItemsPresenter.Style>
<Style TargetType="ItemsPresenter">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ItemCount}" Value="1">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsPresenter.Style>
</ItemsPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>

Categories

Resources