Reputation: 29
I have a DataGrid that is using Virtualization and one of the columns uses a DataGridTemplateColumn with ComboBox inside. However when I scroll left/right in the DataGrid (moving the ComboBox column out of and then into view) the ComboBox loses its selection.
Setting EnableColumnVirtualization="False" does fix the problem, but then I obviously lose virtualization for columns.
Is there a solution that doesn't involve disabling virtualization?
I've put together a simple solution to demonstrate the issue. If you run it and scroll left to right really fast, you'll see the ComboBox eventually becomes empty and shows a red border around it.
XAML:
<Window x:Class="SimpleReproTest.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" Loaded="Window_Loaded">
<Grid>
<DataGrid x:Name="MyGrid" AutoGenerateColumns="False" EnableColumnVirtualization="True" EnableRowVirtualization="True"
VirtualizingStackPanel.VirtualizationMode="Standard" VirtualizingStackPanel.IsVirtualizing="True">
<DataGrid.Columns>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="ComboBox Column"/>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DummyItems}"
SelectedValue="{Binding DummySelection}"
SelectedValuePath="Key"
DisplayMemberPath="Value"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
<DataGridTextColumn Header="DummyColumn" Binding="{Binding Dummy}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
Code Behind:
using System.Collections.Generic;
using System.Windows;
using System.Collections.ObjectModel;
namespace SimpleReproTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<DummyColumn> MyData;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MyData = new ObservableCollection<DummyColumn>();
for (int i = 0; i < 50; i++)
MyData.Add(new DummyColumn());
MyGrid.ItemsSource = MyData;
}
}
public class DummyColumn
{
public ObservableCollection<KeyValuePair<int, string>> DummyItems {get; set;}
public string Dummy { get; set; }
public int DummySelection { get; set; }
public DummyColumn()
{
Dummy = "...";
DummySelection = 0;
DummyItems = new ObservableCollection<KeyValuePair<int,string>>();
DummyItems.Add(new KeyValuePair<int,string>(0, "Item 0"));
DummyItems.Add(new KeyValuePair<int,string>(1, "Item 1"));
}
}
}
Upvotes: 0
Views: 1639
Reputation:
The key point of my answer is that you simply need to bind the Text property of your combo with UpdateSourceTrigger equals to Property Changed.
That's the only correct solution. Don't be confused by the other irrelevant details. If you know WPF very well (and very few people here do unfortunately) you must be aware the OnPropertyChanged (or equivalent notifier) are absolutely useless when the change of a UI property stems from the UI object itself.
Try with this xaml
<DataTemplate>
<ComboBox ItemsSource="{Binding DummyItems}"
SelectedValue="{Binding DummySelection}"
SelectedValuePath="Key"
Text="{Binding DummySel, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Value"/>
</DataTemplate>
and ViewModel
private string dummySel;
public string DummySel
{
get { return dummySel; }
set { dummySel = value;
//OnPropertyChanged(() => DummySel);
}
}
private int dummySelection;
public int DummySelection {
get { return dummySelection; }
set {
dummySelection = value;
//OnPropertyChanged(()=>DummySelection);
}
}
Upvotes: 1