【问题标题】:WPF DataGrid TextBoxes retaining previous values when there are multiple validation errorsWPF DataGrid TextBoxes 在存在多个验证错误时保留以前的值
【发布时间】:2017-04-13 13:52:53
【问题描述】:

我创建了一个DataGrid,其中有两列都使用TextBoxs 来编辑ViewModel 的属性。当两列都有验证错误,并且从 ViewModel 更改属性值时,在其中一个单元格中进入编辑模式会保留之前编辑的值。

这是一个简短的例子:

查看

<Window ...>
    <Window.DataContext>
        <ViewModels:MainPresenter />
    </Window.DataContext>

    <DockPanel>
        <Button Command="{Binding ResetValuesCommand}"
                Margin="5" DockPanel.Dock="Top">Reset Values</Button>

        <DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Value 1"
                    Binding="{Binding Value1, ValidatesOnDataErrors=True}" />
                <DataGridTextColumn Header="Value 2"
                    Binding="{Binding Value2, ValidatesOnDataErrors=True}" />
            </DataGrid.Columns>
        </DataGrid>
    </DockPanel>
</Window>

视图模型

public class MainPresenter : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public IEnumerable<ItemPresenter> Items { get; }
        = new ObservableCollection<ItemPresenter> {new ItemPresenter()};

    public ICommand ResetValuesCommand => new ResetCommand(Items);

    private class ResetCommand : ICommand
    {
        private readonly IEnumerable<ItemPresenter> _items;

        public ResetCommand(IEnumerable<ItemPresenter> items) { _items = items; }

        public void Execute(object parameter) => _items.ToList().ForEach(i => i.Reset());

        public bool CanExecute(object parameter) => true;

        public event EventHandler CanExecuteChanged { add { } remove { } }
    }
}

public class ItemPresenter : INotifyPropertyChanged, IDataErrorInfo
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Value1 { get; set; } = "A";

    public string Value2 { get; set; } = "B";

    public string this[string columnName] => "ERROR";

    public string Error => "ERROR";

    public void Reset()
    {
        Value1 = "A";
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value1)));
        Value2 = "B";
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value2)));
    }
}

复制步骤

运行应用程序时,两列都被突出显示为无效。

  • 双击“值 1”列中的单元格(当前值为“A”)并更改它,例如到“Z”;
  • 按回车键(或等效键)提交更改;
  • 按下“重置值”按钮(导致我们刚刚编辑的单元格变为“A”);
  • 再次双击“值 1”列中的单元格。

“值 1”列中的单元格变为编辑模式,值再次显示为“Z”。

需要注意的一点:仅当其他列出现验证错误时才会发生这种情况。如果这是唯一出现验证错误的列,则编辑模式下的 TextBox 在进入编辑模式时将正确显示“A”。

部分修复

奇怪的是,将绑定中的 Mode 显式设置为 TwoWay(可能是默认值,因为这是明显的行为)解决了问题。

但是,如果我想要一些自定义单元格模板(并将DataGridTextColumns 替换为DataGridTemplateColumnss)但仍使用TextBox 进行编辑:

<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Value 1">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                    <TextBlock Text="{Binding Value1, ValidatesOnDataErrors=True}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                    <TextBox Text="{Binding Value1, ValidatesOnDataErrors=True}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn Header="Value 2">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                    <TextBlock Text="{Binding Value2, ValidatesOnDataErrors=True}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                    <TextBox Text="{Binding Value2, ValidatesOnDataErrors=True}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

我遇到了同样的问题,但将绑定模式显式设置为 TwoWay 并不能解决问题。

我是否在某处做错了,我忽略了?或者,是否有人对此有解决方法?

【问题讨论】:

    标签: c# wpf xaml datagrid idataerrorinfo


    【解决方案1】:

    我找到了解决方法。

    如果我改为使用INotifyDataErrorInfo仅适用于 .NET 4.5 及更高版本),那么它会按预期工作。

    视图模型

    public class ItemPresenter : INotifyPropertyChanged, INotifyDataErrorInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    
        public string Value1 { get; set; } = "A";
    
        public string Value2 { get; set; } = "B";
    
        public IEnumerable GetErrors(string propertyName) => new[] { "ERROR" };
    
        public bool HasErrors => true;
    
        public void Reset()
        {
            Value1 = "A";
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value1)));
            ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Value1)));
            Value2 = "B";
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value2)));
            ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Value2)));
        }
    }
    

    查看

    <DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Value 1">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                        <TextBlock Text="{Binding Value1}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                        <TextBox Text="{Binding Value1}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Value 2">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                        <TextBlock Text="{Binding Value2}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
                        <TextBox Text="{Binding Value2}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-14
      • 2011-06-29
      • 1970-01-01
      • 2011-06-14
      • 1970-01-01
      • 2016-01-21
      • 2011-07-03
      • 1970-01-01
      相关资源
      最近更新 更多