I want to regroup my data with an expander that contains the group name and contains all ClassMate name inside.
This is my class Group :
public class Group{
public List<ClassMate> CLGroup { get; set; }
public string GroupName { get; set; }}
My classMate class :
public class ClassMate: INotifyPropertyChanged{
public string Name { get; set; }
public string DisplayName { get; set; }}
I tried to do this with this Xaml but I don't know why it's not working
<DataGrid x:Name="gridMates" ItemsSource="{Binding Groups }" >
<DataGrid.GroupStyle>
<!-- Style for groups at top level. -->
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel>
<TextBlock Text="{Binding Path=GroupName}" />
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsControl ItemsSource="{Binding Path=CLGroup}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=DisplayName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
What am I doing wrong?
Thanks
You need to bind the ItemsSource property to a grouped source collection. The easiest way to do this is to use a CollectionViewSource:
<Grid>
<Grid.Resources>
<CollectionViewSource x:Key="groups" Source="{Binding Groups}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="GroupName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
<DataGrid x:Name="gridMates" ItemsSource="{Binding Source={StaticResource groups}}" AutoGenerateColumns="False">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel>
<TextBlock Text="{Binding Path=Name}" />
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsControl ItemsSource="{Binding Path=Items[0].CLGroup}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=DisplayName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
</Grid>
XAML Design
<Window.Resources>
<Style x:Key="groupheaderstyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<TextBlock Text="{Binding Gropname}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DataGrid x:Name="dgdata" HorizontalAlignment="Left" Height="269" VerticalAlignment="Top" Width="292">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupheaderstyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
XAML Design.CS
public class group
{
public string groupname { get; set; }
public string CLgroup { get; set; }
public string displayname { get; set; }
}
public Window4()
{
InitializeComponent();
ObservableCollection<group> samdata = new ObservableCollection<group>
{
new group{groupname="Group1",CLgroup="xxx",displayname="demo1"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group3",CLgroup="zzz",displayname="demo3"},
new group{groupname="Group3",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group3",CLgroup="yyy",displayname="demo2"},
};
ListCollectionView collection = new ListCollectionView(samdata);
collection.GroupDescriptions.Add(new PropertyGroupDescription("groupname"));
dgdata.ItemsSource = collection;
}
Related
I finish a ListView grouping and add a expander control.
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="Gray" FontSize="16" 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>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
The IsExpanded like
<Expander IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}}">
and I set lv.SelectedIndex to change selection, but it don't work!
I have no idea.
Xaml Design:
<Window.Resources>
<Style x:Key="groupheaderstyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<TextBlock Text="{Binding Gropname}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DataGrid x:Name="dgdata" HorizontalAlignment="Left" Height="269" VerticalAlignment="Top" Width="292">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupheaderstyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
Xaml Design.cs
public class group
{
public string groupname { get; set; }
public string CLgroup { get; set; }
public string displayname { get; set; }
}
public Window4()
{
InitializeComponent();
ObservableCollection<group> samdata = new ObservableCollection<group>
{
new group{groupname="Group1",CLgroup="xxx",displayname="demo1"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
};
ListCollectionView collection = new ListCollectionView(samdata);
collection.GroupDescriptions.Add(new PropertyGroupDescription("groupname"));
dgdata.ItemsSource = collection;
}
Hy everyone,
i have a problem to get the foreground color of an expander Header changed after modifying an item of that expander.
Here is my WPF snippet, which i already have:
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Margin="10,0,0,0" IsExpanded="True"
BorderBrush="{Binding ., Converter={StaticResource BackgroundHeader}}">
<Expander.Background>
<Binding Path="." Converter="{StaticResource BackgroundHeader}" />
</Expander.Background>
<Expander.Header >
<DockPanel Background="{Binding .,Converter={StaticResource BackgroundHeader}}">
<TextBlock FontWeight="Bold" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding ., Converter={StaticResource ForegroundHeader}}"
Margin="5,0,0,0"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
I have already tried to Refresh my ListCollectionView after changing values, but the performance is really bad.
MyListCollectionView.Refresh();
Thanks for any help...
UPDATE:
Here is my WPF Snippet within the GroupStyle is defined:
<DataGrid x:Name="DataGridItemList" Grid.Row="1" ItemsSource="{Binding Path= CurrentWorkItemList}"
SelectedItem="{Binding Path= CurrentSelectedItem}" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<.../>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="SelectedCol" Header=" " CanUserResize="False">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<CheckBox x:Name="ckbIsSelected" Click="CkbIsSelected_OnClick" IsChecked="{Binding Path = IsSelected, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"
IsEnabled="{Binding Path = Mandatory, Converter={StaticResource InvertBoolean}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<.../>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.GroupStyle>
<!-- Style for groups at top level. -->
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Margin="10,0,0,0" IsExpanded="True"
BorderBrush="{Binding ., Converter={StaticResource BackgroundHeader}}">
<Expander.Background>
<Binding Path="." Converter="{StaticResource BackgroundHeader}" />
</Expander.Background>
<Expander.Header >
<DockPanel Background="{Binding .,Converter={StaticResource BackgroundHeader}}">
<TextBlock FontWeight="Bold" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding ., Converter={StaticResource ForegroundHeader}}"
Margin="5,0,0,0"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="White" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
...and the ViewModel for this View:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
...
}
#region Properties
private ListCollectionView _currentWorkItemList;
public ListCollectionView CurrentWorkItemList
{
get { return _currentWorkItemList; }
set
{
_currentWorkItemList = value;
OnPropertyChanged("CurrentWorkItemList");
}
}
private MyClass _CurrentSelectedItem;
public MyClass CurrentSelectedItem
{
get { return _CurrentSelectedItem; }
set
{
var saved = CheckChangesAndSaveItem(_CurrentSelectedItem);
_CurrentSelectedItem = value;
if (_CurrentSelectedItem != null)
{
SetCurrentSelectedItemToCache(_CurrentSelectedItem);
}
OnPropertyChanged("CurrentSelectedItem");
}
}
private MyClass _selectedItemCache;
public MyClass SelectedItemCache
{
get { return _selectedItemCache; }
set
{
_selectedItemCache = value;
OnPropertyChanged("SelectedItemCache");
}
}
#endregion
#region Public Functions/Commands
public void InitViewModel()
{
using (new WaitCursor())
{
CurrentWorkItemList = new ListCollectionView(...);
if (CurrentWorkItemList.GroupDescriptions != null)
{
CurrentWorkItemList.GroupDescriptions.Add(new PropertyGroupDescription("Group1"));
CurrentWorkItemList.GroupDescriptions.Add(new PropertyGroupDescription("Group2"));
}
}
}
public void CheckSaveAndCloneCurrentItem()
{
CheckSaveAndCloneCurrentItem(_CurrentSelectedItem);
}
#endregion
#region Internal Functions
private void CheckSaveAndCloneCurrentItem(MyClass currentItem)
{
var saved = CheckChangesAndSaveItem(currentItem);
SetCurrentSelectedItemToCache(currentItem);
}
private void SetCurrentSelectedItemToCache(MyClass currentItem)
{
if (currentItem != null)
{
SelectedItemCache = currentItem.Clone();
}
}
private bool CheckChangesAndSaveItem(MyClass currentItem)
{
var eItemIsSelected = ViewModels.DataAdapter.GetWorkItem().IsSelected;
if (currentItem.IsSelected != SelectedItemCache.IsSelected || SelectedItemCache == null ||
(currentItem.IsSelected != eItemIsSelected))
{
currentItem.Group1 = currentItem.Group1.ToString();
ViewModels.DataAdapter.SaveAllListItem(currentItem);
return true;
}
return false;
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
#endregion
}
I have a datagrid, in one of the columns I want to display a string - in each cell in the column a different string(that I get from the user) that looks like this: "data1, data2, data3, ..." and make each datai(data1,data2,...) clickable.
how can I achieve that?
Here is edited version:
Xaml (put it inside the <DataGridTemplateColumn.CellTemplate):
<DataTemplate DataType="{x:Type soDataGridHeplAttempt:ClicableItemsModel}">
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding ClickableItems}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Button Width="70" Content="{Binding }" Style="{StaticResource ButtonInCellStyle}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Command}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DataTemplate>
Xaml resources use this if you want to edit the button content:
<Style x:Key="ButtonInCellStyle" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Background="{x:Null}" MaxWidth="40" BorderBrush="{x:Null}" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}}, Path=Content, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
HorizontalAlignment="Center" VerticalAlignment="Center" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Text}">
</TextBox>
</DataTemplate>
</Setter.Value>
</Setter>
Viewmodel:
private ICommand _command;
public ObservableCollection<ClicableItemsModel> Strings { get; set; }
public ICommand Command
{
get { return _command ?? (_command = new RelayCommand<object>(MethodOnCommmand)); }
}
private void MethodOnCommmand(object obj)
{
}
Clickable Items model code (create the ClicableItemsModel class an put it there):
public ObservableCollection<String> ClickableItems { get; set; }
when running:
regards,
I have following control template:
public sealed partial class ItemSelectorControl : Control
{
...
public ICommand SelectionCommand
{
get { return (ICommand)GetValue(SelectionCommandProperty); }
set { SetValue(SelectionCommandProperty, value); }
}
public static readonly DependencyProperty SelectionCommandProperty =
DependencyProperty.Register("SelectionCommand", typeof(ICommand), typeof(ItemSelectorControl), new PropertyMetadata(null));
public ItemSelectorControl()
{
DefaultStyleKey = typeof(ItemSelectorControl);
}
...
}
and the corresponding theme style:
<Style TargetType="controls:ItemSelectorControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ItemSelectorControl">
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock
Style="{StaticResource SectionHeader}"
Text="{TemplateBinding Headline}"
Visibility="{TemplateBinding HeadlineVisibility}"/>
<ItemsControl
x:Name="CurrencyItemPanel"
ItemsSource="{TemplateBinding ItemCollection}"
MaxHeight="{TemplateBinding MaximumItemsControlHeight}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Style="{StaticResource ItemSelectorButtonStyle}"
Command="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectionCommand}"
CommandParameter="{Binding Path=Code}">
<interactivity:Interaction.Behaviors>
<behaviour:ItemSelectorVisualStateBehaviour
StateChangeTrigger="{Binding Selected, Mode=TwoWay}"/>
</interactivity:Interaction.Behaviors>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How do I have to write the command binding?
Command="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectionCommand}"
In WPF I would work with FindAncestor but since that is not available in WinRT I don't not how to bind? I can't use DataContext.SelectionCommand because the current DataContext is the ViewModel.
I have the following DataGrid in WPF with two groups.
First group is a bool flag which represents if a person is active/inactive.
The second group (or sub-group) is the ID of each person.
Each person can have multiple cities, therefore the grouping for the ID, because each person is shown multiple in the DataGrid.
Here is the XAML:
<DataGrid CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding DataSource}">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="True">
<Setter Property="Background" Value="{StaticResource ActiveBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="False">
<Setter Property="Background" Value="{StaticResource InactiveBrush}"/>
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name, Converter={StaticResource BoolToTextConverter}}" Margin="5 2 5 2"/>
<TextBlock Text=":" Margin="0 2 5 2"/>
<TextBlock Text="{Binding ItemCount}" Margin="0 2 0 2"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="LightSteelBlue">
<TextBlock Text="{Binding Name}" Foreground="White" Margin="5 2 5 2"/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<DockPanel>
<Button BorderThickness="0" Content="Edit" Margin="3"
Command="{Binding Commands.Edit}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</DockPanel>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="ID" Binding="{Binding ID}" IsReadOnly="True"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" IsReadOnly="True"/>
<DataGridTextColumn Header="City" Binding="{Binding City}" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
It all works fine!
However, I don't like the blue row for each sub-group.
What I want to achieve is the grouping style in the following image:
For each sub-group I want the Edit button and the ID to appear only once per person.
How would I do this? Is it possible in XAML only or should I remove the reduntant content in code-behind?
Edit
Here some test data:
public class Person
{
public Person(bool active, int id, string name, string city)
{
Active = active;
ID = id;
Name = name;
City = city;
}
public bool Active { get; set; }
public int ID { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
var data = new ObservableCollection<Person>
{
new Person(true, 233, "Max", "New York"),
new Person(true, 233, "Max", "Los Angeles"),
new Person(true, 314, "John", "Paris"),
new Person(true, 578, "Mary", "Vienna"),
new Person(true, 782, "Susan", "Rome"),
new Person(true, 782, "Susan", "Prague"),
new Person(true, 782, "Susan", "San Francisco"),
new Person(false, 151, "Henry", "Chicago")
};
DataSource = new ListCollectionView(data);
}
private ListCollectionView _dataSource;
public ListCollectionView DataSource
{
get { return _dataSource; }
set
{
_dataSource = value;
_dataSource.GroupDescriptions.Add(new PropertyGroupDescription("Active"));
_dataSource.GroupDescriptions.Add(new PropertyGroupDescription("ID"));
}
}
I would highly recommend changing the data structure to:
public class Person {
public bool Active { get; set; }
public int ID { get; set; }
public string Name { get; set; }
public Collection Cities { get; set; }
}
Otherwise you can change this GroupStyle
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="LightSteelBlue">
<TextBlock Text="{Binding Name}" Foreground="White" Margin="5 2 5 2"/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
To
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="EditButtonColumn" />
<ColumnDefinition SharedSizeGroup="IDColumn" />
<ColumnDefinition SharedSizeGroup="NameColumn" />
<ColumnDefinition SharedSizeGroup="PresenterColumn" Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" BorderThickness="0" Content="Edit" Margin="3"
CommandParameter="{Binding Path=Items[0]}" />
<TextBlock Grid.Column="1" Text="{Binding Path=Items[0].ID}" />
<TextBlock Grid.Column="2" Text="{Binding Path=Items[0].Name}" />
<ItemsPresenter Grid.Column="3" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
Change the template to suit your needs