【问题标题】:Is this a WPF Datagrid bug? [closed]这是 WPF 数据网格错误吗? [关闭]
【发布时间】:2012-07-19 17:06:52
【问题描述】:

我有以下概念证明:

XAML 窗口:

<Window x:Class="WpfApplication1.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">

<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" >
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}" />
        <DataGridTemplateColumn >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding Mode=TwoWay, Path=Enabled}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
</Window>

后面的代码:

using System.Collections.ObjectModel;
using System.Windows;

namespace WpfApplication1
{
public partial class MainWindow : Window
{
    public ObservableCollection<Data> Items { get; private set; }

    public MainWindow()
    {
        InitializeComponent();
        this.Items = new ObservableCollection<Data>();
        this.DataContext = this;
        for (int index = 0; index < 30; index++)
        {
            this.Items.Add(new Data() {Enabled = true });   
        }
    }
}

public class Data
{
    public bool Enabled { get; set; }
}
}

执行应用程序,取消选中顶部的一些框,向下滚动,再次更改一些框并向上滚动。瞧,复选框又被选中了!

我是否遗漏了什么,或者我应该向 Microsoft 填写一个错误?

编辑:感谢您的回复,但它与 INotify 或 Checkbox 无关,TextBox 和 INotify 也会发生同样的情况。滚动后您不需要单击复选框,只需取消选中一些,向下滚动,向上滚动并瞧,它们会再次被选中。检查此代码:

<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" >
    <DataGrid.Columns>
        <DataGridTemplateColumn >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding Mode=TwoWay, Path=Enabled}" />
                        <TextBox Text="{Binding Text}" />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
</Window>

以及背后的代码:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace WpfApplication1
{
public partial class MainWindow : Window
{
    public ObservableCollection<Data> Items { get; private set; }

    public MainWindow()
    {
        InitializeComponent();
        this.Items = new ObservableCollection<Data>();
        this.DataContext = this;
        for (int index = 0; index < 30; index++)
        {
            this.Items.Add(new Data() { Enabled = true, Text = index.ToString() });
        }
    }
}

public class Data : INotifyPropertyChanged
{
    private bool _enabled;
    public bool Enabled
    {
        get { return _enabled; }
        set
        {
            if (value != _enabled)
            {
                _enabled = value;
                this.OnPropertyChanged("Enabled");
            }
        }
    }

    private string _text;
    public string Text
    {
        get { return _text; }
        set
        {
            if (value != _text)
            {
                _text = value;
                this.OnPropertyChanged("Text");
            }
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string name)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion
}
}

【问题讨论】:

  • 如果您使Data 继承自INotifyPropertyChanged 并使用属性更改通知,您的结果会改变吗?
  • 尝试关闭回收。集合是否被调用?如果不是 UpdateSourceTrigger="PropertyChanged"。就像 Rachel 说的那样,INotify。
  • 我会尝试 Rachel 的建议。
  • 我会按照 Rachel 的建议去做,然后尝试 EnableRowVirtualization="false"。
  • @Rachel 不,结果不会改变:(

标签: .net wpf datagrid


【解决方案1】:

此问题与回收无关。事实上,禁用回收隐藏了真正的问题:您的 Data 对象属性永远不会更新。尝试在EnabledText 设置器中设置断点,您会发现更改文本或选中/取消选中该框时不会发生任何事情。当您滚动并向后滚动时,会从对象中重新读取该属性,并且由于它没有更改,因此复选框会正确更新以匹配 Enabled 属性。

DataGrid 意味着默认情况下所有行都处于显示模式,用户在需要时切换到当前选定行的编辑模式。在用户验证整行之前,不会提交这些值。

在幕后,为整行创建了一个隐式BindingGroup,有效地将所有绑定设置为UpdateSourceTrigger.Explicit。当用户完成对行的编辑时,将提交此绑定组。在您的情况下,由于没有BeginEdit,因此不会有任何CommitEdit,并且这些值永远不会更新。

这里有几种解决方案:

  • 使用没有这种“切换到编辑模式”行为的其他控件,例如ListView
  • 在每个绑定上强制 UpdateSourceTriggerPropertyChangedLostFocus
  • 更改用户使用网格的方式以符合DataGrid 行为。

【讨论】:

    【解决方案2】:

    最后我在 Microsoft 输入了一个缺陷,因为无论是否使用 VirtualRows,这都不是预期的工作方式。

    错误报告here

    【讨论】:

      猜你喜欢
      • 2012-12-04
      • 2013-12-12
      • 2014-02-08
      • 2013-04-02
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多