I have a datagrid and want to bind its item source as CollectionViewSource which has the source of List. But binding is not working. Please check my code in below. Note that i dont want to use ObservableCollection because of virtualization problem while grouping.
<UserControl.Resources>
<CollectionViewSource x:Key="weightItemCollection" Source="{Binding Path=LoadCaseWeightItems}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="LocalizedGroupName"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="LocalizedGroupName"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<DataGrid x:Name="customLoadCaseGrid"
ItemsSource="{Binding Source={StaticResource weightItemCollection}}" />
User Control code
public partial class WeightItem : INotifyPropertyChanged
{
List<WeightItemData> loadCaseWeightItems;
public List<WeightItemData> LoadCaseWeightItems { get { return loadCaseWeightItems; } set { loadCaseWeightItems = value; OnPropertyChanged(nameof(LoadCaseWeightItems)); } }
public event PropertyChangedEventHandler PropertyChanged;
public WeightItem()
{
InitializeComponent();
loadCaseWeightItems = new List<WeightItemData>();
//Here i add items to loadCaseWeightItems
}
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
This should work:
<UserControl.Resources>
<CollectionViewSource x:Key="weightItemCollection"
Source="{Binding Path=LoadCaseWeightItems,RelativeSource={RelativeSource AncestorType=UserControl}}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="LocalizedGroupName"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="LocalizedGroupName"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<Grid>
<DataGrid x:Name="customLoadCaseGrid" ItemsSource="{Binding Source={StaticResource weightItemCollection}}" />
</Grid>
You may also set the Source programmatically:
public WeightItem()
{
InitializeComponent();
loadCaseWeightItems = ...;
((CollectionViewSource)Resources["weightItemCollection"]).Source = loadCaseWeightItems;
}
Related
I am using a CollectionViewSource and have set up the CollectionViewSource.SortDescription property in xaml for sorting the collection on a particular property.
However, now I have a case wherein if certain condition is true, or collection is of particular type, I don't need to apply the sorting, but rather to just bind the collection as it is from the view model.
I don't want to move the sorting out of XAML to view model, since it complicates the matter. I want to leave sorting to CollectionViewSource.SortDescription, however want to know if there is a way to turn it off based on some flag. E.g. I can expose a property IgnoreSort in my view model and just somehow consume it to turn the CollecitonViewSource sorting off.
Following is the xaml code-
Resource:
<UserControl.Resources>
<CollectionViewSource x:Key="PeopleItemsSource" Source="{Binding Department.ActivePeople}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="DisplaySortOrder" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</UserControl.Resources>
And here is the control using the resource declared above
<ItemsControl x:Name="peopleitems"
Grid.Row="1"
ItemsSource="{Binding Source={StaticResource PeopleItemsSource}}"/>
Note: Item template is not added here to simplify the xaml.
Here's a small example I wrote, I don't think you'll have issues adapting it to your project, it uses DataTriggers to conditionally choose the itemssource, it doesn't use code behind, the code behind you see here is just to setup the datacontext, the items collection etc. Copy paste this code into a new WPF project and see it working
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
>
<Window.Resources>
<CollectionViewSource x:Key="colSrc" Source="{Binding MyList}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<Style TargetType="ItemsControl" x:Key="ic">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSorted}" Value="True">
<Setter Property="ItemsSource" Value="{Binding Source={StaticResource ResourceKey=colSrc}}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsSorted}" Value="False">
<Setter Property="ItemsSource" Value="{Binding MyList}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<CheckBox IsChecked="{Binding IsSorted}"/>
<ItemsControl Grid.Row="1" Style="{StaticResource ic}"/>
</StackPanel>
</Grid>
MainWindow.xaml.cs
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window,INotifyPropertyChanged
{
private bool isSorted;
public bool IsSorted
{
get
{
return isSorted;
}
set
{
isSorted = value;
OnPropertyChanged("IsSorted");
}
}
private ObservableCollection<string> myList;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<string> MyList
{
get
{
return myList;
}
set
{
myList = value;
this.OnPropertyChanged("MyList");
}
}
public MainWindow()
{
InitializeComponent();
this.MyList = new ObservableCollection<string>() {
"C",
"B",
"A"
};
this.DataContext = this;
}
private void OnPropertyChanged(string p)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
}
you must do it by code - add or remove the SortProperties
internal void Sort(PropertyModel model)
{
PropertyViewModel prop = SortProperties.Find(p => p.Data == model);
IEnumerable<SortDescription> result =
Books.SortDescriptions.Cast<SortDescription>().Where(p => p.PropertyName == prop.Data.FullName);
if (result != null && result.Count() == 1)
{
Books.SortDescriptions.Remove(result.First());
}
else
{
Books.SortDescriptions.Add(new SortDescription(prop.Data.FullName, ListSortDirection.Ascending));
}
RaisePropertyChanged("Books");
}
I am aware that as DataGrid columns aren't part of the Visual Tree, you can't bind the visibility property of the columns directly to a boolean property in your VM. You have to do it another way. Below is the way I have done it:
public class LocalVm
{
public static ObservableCollection<Item> Items
{
get
{
return new ObservableCollection<Item>
{
new Item{Name="Test1", ShortDescription = "Short1"}
};
}
}
public static bool IsDetailsModeEnabled
{
get { return true; }
}
}
public class Item : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
private string _shortDescription;
public string ShortDescription
{
get
{
return _shortDescription;
}
set
{
_shortDescription = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<Window x:Class="Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DataContext="{d:DesignInstance Type=local:LocalVm}"
Title="MainWindow" Height="350" Width="525"
Name="MyWindow">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding Size}"
Visibility="{Binding DataContext.IsDetailsModeEnabled,
Source={x:Reference MyWindow},
Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<StaticResource ResourceKey="ThatPeskyColumn"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
However, in my xaml window, there is an error on the "visibility" property: "Object reference not set to an instance of an object". If I remove the source and converter part, the error goes but it doesn't bind properly. What I am doing wrong?
thanks in advance
As I can see from the code you've provided, IsDetailsModeEnabled property is static. To bind to static property in that case, you may just create your VM as a static resource, bind to its static property and set it to Window DataContext later:
<Window.Resources>
<local:LocalVm x:Key="vm" />
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding ShortDescription}"
Visibility="{Binding Path = IsDetailsModeEnabled,
Source={StaticResource vm},
Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
<Window.DataContext>
<StaticResource ResourceKey="vm"/>
</Window.DataContext>
From the other hand, more classical approach in that case would be with a proxy Freezable object, described here:
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
XAML
<Window.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding ShortDescription}"
Visibility="{Binding Path=Data.IsDetailsModeEnabled,
Source={StaticResource proxy},
Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
I am trying to bind the SelectedIndex property of combobox to my ViewModel. Here is the code.
Xaml:
<ComboBox x:Name="BloodGroupFilter" SelectedIndex="{Binding Path=SelectedBloodGroupIndex, Mode=TwoWay}">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem Foreground="red" FontStyle="Italic">No Filter</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource BloodGroupEnum}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
ViewModel
private int _selectedBloodGroupIndex = 4;
public int SelectedBloodGroupIndex {
get { return _selectedBloodGroupIndex; }
set {
_selectedBloodGroupIndex = value;
}
}
As you can see I am trying to set the SelectedIndex of combobox to "4". This doesn't happen and SelectedIndex is set to 0. Also, when user selects a particular item of the combobox, I was expecting that the ViewModel's SelectedBloodGroupIndex property will update itself to the currently selected item of combobox, but this doesn't happen either. The ViewModel property is never invoked(both set and get). Any reasons why binding is failing for the above code.
Update
<UserControl.Resources>
<ObjectDataProvider x:Key="BloodGroupEnum" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="enums:BloodGroup" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</UserControl.Resources>
You need to Notify Property changed in the setter of SelectedBloodGroupIndex of your ViewModel . I hope you do have the idea of PropertyChanged event.
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myWindow="clr-namespace:WpfApplication4"
Title="MainWindow" Height="800" Width="800" WindowStartupLocation="CenterScreen">
<Grid>
<ComboBox SelectedIndex="{Binding SelectedIndex}">
<ComboBoxItem Content="1"/>
<ComboBoxItem Content="2"/>
<ComboBoxItem Content="3"/>
<ComboBoxItem Content="4"/>
<ComboBoxItem Content="5"/>
</ComboBox>
</Grid>
public partial class MainWindow :Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
public class MyViewModel :INotifyPropertyChanged
{
public MyViewModel()
{
SelectedIndex = 2;
}
private int _selectedIndex;
public int SelectedIndex
{
get
{
return _selectedIndex;
}
set
{
_selectedIndex = value;
Notify("SelectedIndex");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void Notify(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I have a view model with some fields, i.e.
type ViewModel =
member x.a = [1;2;3]
member x.b = [4;5;6]
member x.c = [7]
and in WPF application places some views, as:
<Control.Resources>
<DataTemplate x:Key="ItemTempl">
<TextBlock Text="{Binding}" />
</DataTemplate>
<DataTemplate x:Key="SomeTempl">
<ListBox ItemsSource="{Binding}"
ItemTemplate="{StaticResource ItemTempl}" />
</DataTemplate>
</Control.Resources>
<StackPanel>
<TabControl x:Name="ListBoxViewPresenter">
<TabItem Header="vm.a" Content="{Binding vm.a}"
ContentTemplate="{StaticResource SomeTempl}"/>
<TabItem Header="vm.b" Content="{Binding vm.b}"
ContentTemplate="{StaticResource SomeTempl}"/>
<TabItem Header="vm.c" Content="{Binding vm.c}"
ContentTemplate="{StaticResource SomeTempl}"/>
</TabControl>
<ListBox x:Name="ListBoxViewPresenter">
<ListBoxItem Content="{Binding vm.a}"
ContentTemplate="{StaticResource SomeTempl}" />
<ListBoxItem Content="{Binding vm.b}"
ContentTemplate="{StaticResource SomeTempl}" />
<ListBoxItem Content="{Binding vm.c}"
ContentTemplate="{StaticResource SomeTempl}" />
</ListBox>
</StackPanel>
What should I do to achieve such behavior:
when you clicked on some element in vm.a/b/c in ListBoxViewPresenter so same element in ListBoxViewPresenter is must selected in corresponding TabItem.
UPD:
Specifically my real problem, changing from origin topic.
I have ViewModel with fields: onelines, twolines... and a field with name selected_scheme.
In xaml:
<TreeViewItem Header="{Binding Path=name}" x:Name="ProjectArea">
<TreeViewItem Header="Однониточные планы" Style="{StaticResource MyTreeViewItem}">
<ContentPresenter Content="{Binding onelines}" ContentTemplate="{StaticResource SchemeWrapperTemplate}" />
</TreeViewItem>
<TreeViewItem Header="Двухниточные планы" Style="{StaticResource MyTreeViewItem}">
<ContentPresenter Content="{Binding twolines}" ContentTemplate="{StaticResource SchemeWrapperTemplate}" />
</TreeViewItem>
And data template:
<DataTemplate x:Key="SchemeWrapperTemplate">
<ListBox ItemsSource="{Binding schemes}"
ItemTemplate="{StaticResource SchemeTemplate}"
SelectedItem="{Binding selected_scheme}">
<ListBox.Style>
In other place of the program:
<Grid Grid.Row="1">
<TextBlock Text="{Binding selected_scheme.path}" />
</Grid>
And when you click on some ListBoxes then selected item not changing if you click on a yet SelectedItems.
First of all you should define the ItemsSource of your TabItem and ListBox in the ViewModel they are bound too.
Then you can bind their SelectedItem to a property in your ViewModel.
Here is a code sample (I was too lazy to create a seperate ViewModel class, hence it is mixed with my main window class, but you get the idea...) :
Codebehind :
namespace WpfApplication13
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private object _currentlySelectedItem;
public object CurrentlySelectedItem
{
get { return _currentlySelectedItem; }
set
{
_currentlySelectedItem = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("CurrentlySelectedItem"));
}
}
}
public class MyClass
{
public string MyString { get; set; }
public MyClass(string myString)
{
this.MyString = myString;
}
}
private List<MyClass> _myItemsSource = new List<MyClass>
{
new MyClass("toto"),
new MyClass("tata")
};
public List<MyClass> MyItemsSource
{
get { return _myItemsSource; }
set { _myItemsSource = value; }
}
public object A
{
get { return "toto"; }
}
public object B
{
get { return "tata"; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
}
}
xaml :
<Window x:Class="WpfApplication13.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<TabControl x:Name="ListBoxViewPresenter"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource}" />
<ListBox x:Name="ListBoxViewPresenter2"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource}" />
</StackPanel>
</Grid>
</Window>
New answer after you edited :
It does not make much sense to bind the same object to the SelectedItem property of two different lists that contain different elements. You have to redesign your application or you may be confronted to many problems due to this strange design in the futur.
Still, you can achieve want you want to do with a little codebehing. When the user clicks on one of your ListBox, you set the selected item of your other listbox to null. Then you will be notified when you re-click on the first listbox since the selection goes from null to something.
xaml:
<Window x:Class="WpfApplication13.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<ListBox x:Name="ListBoxViewPresenter"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource}" />
<ListBox x:Name="ListBoxViewPresenter2"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource2}" />
</StackPanel>
</Grid>
</Window>
codebehind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.ComponentModel;
namespace WpfApplication13
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private object _currentlySelectedItem;
public object CurrentlySelectedItem
{
get { return _currentlySelectedItem; }
set
{
_currentlySelectedItem = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("CurrentlySelectedItem"));
}
}
}
private List<int> _myItemsSource = new List<int> { 1, 2 };
private List<int> _myItemsSource2 = new List<int> { 3, 4 };
public List<int> MyItemsSource
{
get { return _myItemsSource; }
set { _myItemsSource = value; }
}
public List<int> MyItemsSource2
{
get { return _myItemsSource2; }
set { _myItemsSource2 = value; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
ListBoxViewPresenter.PreviewMouseDown += ListBoxViewPresenter_PreviewMouseDown;
ListBoxViewPresenter2.PreviewMouseDown += ListBoxViewPresenter2_PreviewMouseDown;
}
void ListBoxViewPresenter_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
ListBoxViewPresenter2.SelectedItem = null;
}
void ListBoxViewPresenter2_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
ListBoxViewPresenter.SelectedItem = null;
}
}
}
I've got a collection of ViewModels and want to bind a ListBox to them. Doing some investigation I found this.
So my ViewModel look like this (Pseudo Code)
interface IItemViewModel
{
string DisplayName { get; }
}
class AViewModel : IItemViewModel
{
string DisplayName { return "foo"; }
}
class BViewModel : IItemViewModel
{
string DisplayName { return "foo"; }
}
class ParentViewModel
{
IEnumerable<IItemViewModel> Items
{
get
{
return new IItemViewModel[] {
new AItemViewModel(),
new BItemViewModel()
}
}
}
}
class GroupViewModel
{
static readonly GroupViewModel GroupA = new GroupViewModel(0);
static readonly GroupViewModel GroupB = new GroupViewModel(1);
int GroupIndex;
GroupViewModel(int groupIndex)
{
this.GroupIndex = groupIndex;
}
string DisplayName
{
get { return "This is group " + GroupIndex.ToString(); }
}
}
class ItemGroupTypeConverter : IValueConverter
{
object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is AItemViewModel)
return GroupViewModel.GroupA;
else
return GroupViewModel.GroupB;
}
}
And this XAML
<UserControl.Resources>
<vm:ItemsGroupTypeConverter x:Key="ItemsGroupTypeConverter "/>
<CollectionViewSource x:Key="GroupedItems" Source="{Binding Items}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription Converter="{StaticResource ItemsGroupTypeConverter }"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource GroupedItems}}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" FontWeight="bold" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This works somehow, exept of the fact that the binding of the HeaderTemplate does not work. Anyhow I'd prefer omitting the TypeConverter and the CollectionViewSource. Isn't there a way to use a property of the ViewModel for Grouping?
I know that in this sample scenario it would be easy to replace the GroupViewModel with a string an have it working, but that's not an option. So how can I bind the HeaderTemplate to the GroupViewModel?
Ok, I finally solved it myself.
First of all the TypeConverter is unnecessary, because the PropertyGroupDescription can be bound on a PropertyName. So I added a Property 'Group' to IItemViewModel and modified XAML as follows:
<UserControl.Resources>
<CollectionViewSource x:Key="GroupedItems" Source="{Binding Items}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Group"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
Furthermore the HeaderTemplate's DataContext is a CollectionViewGroupInternal and the binding has to look like this:
<DataTemplate>
<TextBlock Text="{Binding Name.DisplayName}" FontWeight="bold" />
</DataTemplate>
Here CollectionViewGroupInternal.Name resolves the actual GroupViewModel.