【问题标题】:WPF - New item row not being shown in DataGrid when not binding to the ItemsSource propertyWPF - 未绑定到 ItemsSource 属性时,新项目行未显示在 DataGrid 中
【发布时间】:2018-03-10 16:57:45
【问题描述】:

我正在尝试基于 WPF 的 DataGrid 控件创建自定义 DataGrid。我创建了另一个名为“ItemsDataSource”的属性,并使用它来绑定来自我的 ViewModel 的集合。当此属性引发 ValueChanged 事件时,它将 ItemsSource 的值设置为 ItemsDataSource 的值。

当网格处于只读模式时,这可以正常工作,但是当我将属性 CanUserAddRows 设置为 True 时,如果 ItemsDataSource 为空,我的 DataGrid 永远不会显示新行来添加新行。但是,如果我将绑定更改回 ItemsSource 而不是我的 ItemsDataSource,DataGrid 会显示新行。

这是我的自定义网格的部分代码:

public partial class NewDataGrid : DataGrid
{
    public NewDataGrid()
    {
        InitializeComponent();

        var dpd = DependencyPropertyDescriptor.FromProperty(ItemsDataSourceProperty, typeof(NewDataGrid));

        dpd?.AddValueChanged(this, (s, a) =>
        {
            ItemsSource = ItemsDataSource.Cast<object>().ToList();
        });
    }

    public IList ItemsDataSource
    {
        get { return (IList)GetValue(ItemsDataSourceProperty); }
        set { SetValue(ItemsDataSourceProperty, value); }
    }

     public static readonly DependencyProperty ItemsDataSourceProperty =
                DependencyProperty.Register("ItemsDataSource", typeof(IList), typeof(NewDataGrid), new PropertyMetadata(null));
} 

这是我在 XAML 中进行绑定的方式:

<WPF:NewDataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
      ItemsDataSource="{Binding Path=DataContext.DataWrapperList, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"
      SelectedValue="{Binding Path=DataContext.SelectedDataWrapper, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"
      AutoGenerateColumns="False"
      Validation.ErrorTemplate="{x:Null}"
      Margin="0"
      VerticalScrollBarVisibility="Auto"
      SelectionMode="Single"
      CanUserAddRows="True"
      CanUserDeleteRows="True"
      IsReadOnly="False">

    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" Width="*" SortMemberPath="Name" />
        <DataGridTextColumn Header="Quantity" Binding="{Binding Path=Quantity}" Width="*" SortMemberPath="Quantity" />
</WPF:PAENewDataGrid>

这是在我的 DataContext 中声明 DataListWrapper 属性的方式:

public ObservableCollection<DataWrapper> DataWrapperList;

这是我的 DataWrapper 类:

public class DataWrapper : BaseWrapper
{
    private DataWrapperDTO _data;

    public DataWrapper()
    {
        _data = new DataWrapperDTO();
    }

    public DataWrapper(DataWrapperDTO data)
    {
        _data = data;
    }

    public string Name
    {
        get { return _data.Name; }
        set
        {
            _data.Name = value;
            RaisePropertyChanged(nameof(Name));
        }
    }

    public int Quantity
    {
        get { return _data.Quantity; }
        set
        {
            _data.Quantity = value;
            RaisePropertyChanged(nameof(Quantity));
        }
    }
}

有谁知道当 CanUserAddRows 属性设置为 True 时如何强制 DataGrid 始终显示这一新行?

【问题讨论】:

  • 您能否提供DataWrapperList 属性。我要检查的另一件事是删除ItemsSource = ItemsDataSource.Cast&lt;object&gt;().ToList(); 中的Cast&lt;object&gt;().ToList()。我目前不在电脑前用 vs 来检查它,但我猜ItemsSource 只是一个List&lt;object&gt;,列表中有一个项目。
  • @MartinBackasch 我已经按照您的建议进行了更改,但仍然无法正常工作:(
  • 直接绑定到 ItemsSource 有什么问题?
  • 与您的问题文本相反,DataListWrapper property 不是属性,而是字段。它可能需要成为一个属性。

标签: c# wpf mvvm wpfdatagrid


【解决方案1】:

在解决这个问题一段时间后,我似乎找到了解决方案。使用 PropertyChangedCallback 注册我的 DependencyProperty 并将 ItemsSource 分配给此回调中的新值,使网格添加空白行以添加新值。

NewDataGrid 类代码现在如下所示:

public partial class NewDataGrid : DataGrid
{
    public NewDataGrid()
    {
        InitializeComponent();
        //Removed the DependencyPropertyDescriptor
    }

    public IList ItemsDataSource
    {
        get { return (IList)GetValue(ItemsDataSourceProperty); }
        set { SetValue(ItemsDataSourceProperty, value); }
    }

    public static readonly DependencyProperty ItemsDataSourceProperty =
            DependencyProperty.Register("ItemsDataSource", typeof(IList), typeof(NewDataGrid), new PropertyMetadata(null, ItemsDataSourceChanged));

    private static void ItemsDataSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var grid = sender as NewDataGrid;
        if (grid == null) return;

        grid.ItemsSource = ((IList)args.NewValue).Cast<object>().ToList();
    }
} 

感谢大家的帮助!

【讨论】:

    【解决方案2】:

    请尽量不要在每次添加新项目时替换 ItemsSource:

    public NewDataGrid()
        {
            InitializeComponent();
    
            ItemsSource = new ObservableCollection<object>();
    
            var dpd = DependencyPropertyDescriptor.FromProperty(ItemsDataSourceProperty, typeof(NewDataGrid));
    
    
            dpd?.AddValueChanged(this, (s, a) =>
            {
                ItemsSource.Clear();
                ItemsSource.Add(ItemsDataSource.Cast<object>().ToList());
            });
        }
    

    【讨论】:

      猜你喜欢
      • 2017-09-18
      • 1970-01-01
      • 1970-01-01
      • 2016-12-10
      • 1970-01-01
      • 2013-06-01
      • 2011-12-17
      • 2013-04-21
      • 1970-01-01
      相关资源
      最近更新 更多