滚动时,WPF DataGrid组合框模板列丢失选择

本文关键字:选择 WPF DataGrid 组合 滚动 | 更新日期: 2023-09-27 18:01:44

我有一个使用虚拟化的DataGrid,其中一个列使用了一个内部带有ComboBox的DataGridTemplateColumn。但是,当我在DataGrid中向左/向右滚动时(将ComboBox列移出然后移到视图中),ComboBox失去了其选择。

设置EnableColumnVirtualization="False"确实解决了这个问题,但显然我失去了列的虚拟化。

是否有一个不涉及禁用虚拟化的解决方案?

我已经整理了一个简单的解决方案来演示这个问题。如果您运行它并快速从左向右滚动,您将看到ComboBox最终变为空,并在其周围显示一个红色边框。

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>

背后的代码:

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"));
        }
    }
}

滚动时,WPF DataGrid组合框模板列丢失选择

我的答案的关键是,你只需要绑定你的组合与UpdateSourceTrigger等于property Changed的Text属性。

这是唯一正确的解决方案。不要被其他无关的细节搞糊涂了。如果你非常了解WPF(不幸的是,这里很少有人了解),你必须意识到OnPropertyChanged(或等效的通知器)在UI属性的更改来自UI对象本身时是绝对无用的。

试试这个xaml

<DataTemplate>
    <ComboBox ItemsSource="{Binding DummyItems}"
          SelectedValue="{Binding DummySelection}"
          SelectedValuePath="Key"
              Text="{Binding DummySel, UpdateSourceTrigger=PropertyChanged}"
          DisplayMemberPath="Value"/>
</DataTemplate>

和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); 
    }
}