【问题标题】:WPF datagrid with MVVM带有 MVVM 的 WPF 数据网格
【发布时间】:2011-10-23 20:34:52
【问题描述】:

我正在尝试将 WPF 中的数据网格绑定到我的 ViewModel,以便它将更新对数据库的任何单元格更改,并允许用户删除行和添加新行。我已经完成了部分工作,但找不到 ADD 和修改的优雅解决方案。 这是xml

<DataGrid AutoGenerateColumns="false" HorizontalAlignment="Left" Margin="26,41,0,0" Name="dataGrid1"   
              ItemsSource="{Binding Path=GetAllItems}" Height="200" VerticalAlignment="Top" Width="266" >
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=ItemListID}" Header="ID" Visibility="Hidden"/>
            <DataGridTextColumn Binding="{Binding Path=ItemName}" Header="Name" Width="4*" />
            <DataGridCheckBoxColumn Binding="{Binding Path=IsActive}" Header="Active" Width="*"  />
        </DataGrid.Columns>

然后在我的视图模型方法中

private ObservableCollection< ItemsList> getAllItems()
{
    using (var context = new InspectorGeneralEntities())
    {
        var query = from I in context.ItemsLists
                    select I;

        var item = new ObservableCollection<ItemsList>(query.ToList());
        return item;
    }
}

在数据网格上删除一行或修改一行不会流入数据库。

a) 我需要在 xaml 代码中创建什么其他绑定来检测这些事件

b) 我如何检测视图模型中已删除的记录或修改的项目,以便在数据上下文不会自动更新时更新它。

【问题讨论】:

    标签: c# wpf mvvm datagrid


    【解决方案1】:

    您可以创建一个新的 ViewModel CLass:ItemGridVM 来表示每个行对象,即 ItemGridVM 公开您在数据网格中绑定的 Item 类属性。 例如:

    public class ItemGridVM : BaseViewModel
        {
        private Item _item;//an instance of Item class
          public int ItemId
                  {
                      get
                      {
                          return _item.ItemId;
                      }
                      set
                      {
                          _item.ItemId = value;
                          //if you want UI changes : raise PropertyChanged Notification and binding in UI should be Update SourceTrigger:PropertyChanged
                      }
            }
       //Contains Commands :UpdateItem,EditItem,DeleteItem
    }
    

    现在在 yourMainViewModel 中,您可以将 ItemGridVM 的 Observable COllection 创建为:

    private ObservableCollection<ItemGridVM> _getAllItems;
    
    public ObservableCollection<ItemGridVM> GetAllItems
    {
    get
                {
                    return _getAllItems;
                }
                set
                {
                    _getAllItems = value;
                    //if u want Observable Collection to get updated on edit either 
                    RaisePropertyChanged("GetAllItems");
    
                }
    }
    

    现在,如果对任何行执行任何操作,命令将绑定到 ItemGridVM。因此,您可以将行详细信息作为公开属性。 我用这个解决了同样的问题。(纯MVVM)

    【讨论】:

      【解决方案2】:

      在您进行更新时,您的数据上下文不存在。您正在使用破坏上下文的“使用”语句。您看到数据的唯一原因是您已强制对您的数据库运行查询(通过 .ToList() 语句)。回答您的问题:

      a) 无需专门用于绑定 b) 在 InspectorGeneralEntities() 上下文中调用 SaveChanges() 将更新数据库中的任何更改。

      【讨论】:

        【解决方案3】:

        我发现您问题中的代码存在一些问题。但是删除一行没有反映在数据库中的原因是 .ToList() - 本质上你正在创建一个新列表,它是 query 的副本,并且网格正在从该副本中删除元素。

        您应该使用 ListCollectionView 并使用 Filter 而不是 linq 语句。

        下面是一个示例,展示了如何做到这一点:

        1) 创建一个名为 ListCollectionViewTest

        的新 WPF 项目

        2) 在 MainWindow.xaml.cs 中剪切&粘贴以下内容(应该在 ViewModel 但我太懒了)

            using System.Collections.Generic;
            using System.Linq;
            using System.Windows;
            using System.Windows.Data;
        
            namespace ListCollectionViewTest
            {
                /// <summary>
                /// Interaction logic for MainWindow.xaml
                /// </summary>
                public partial class MainWindow : Window
                {
                    private List<Employee> equivalentOfDatabase = new List<Employee>()
                                {
                                    new Employee() { FirstName = "John", LastName = "Doe", IsWorthyOfAttention = true },
                                    new Employee() { FirstName = "Jane", LastName = "Doe", IsWorthyOfAttention = true },
                                    new Employee() { FirstName = "Mr.", LastName = "Unsignificant", IsWorthyOfAttention = false },
                                };
        
                    public ListCollectionView TestList { get; set; }
                    public MainWindow()
                    {
                        DataContext = this;
        
                        // This is all the magic you need -------
                        TestList = new ListCollectionView(equivalentOfDatabase);
                        TestList.Filter = x => (x as Employee).IsWorthyOfAttention;
        
                        InitializeComponent();
                    }
        
                    private void Button_Click(object sender, RoutedEventArgs e)
                    {
                        MessageBox.Show(equivalentOfDatabase.Aggregate("Employees are: \n\r", (acc, emp) => acc + string.Format("    - {0} {1}\n\r", emp.FirstName, emp.LastName), x => x));
                    }
                }
        
                public class Employee
                {
                    public string FirstName { get; set; }
                    public string LastName { get; set; }
                    public bool IsWorthyOfAttention { get; set; }
                }
            }
        

        3) 在 MainWindow.xaml 中剪切并粘贴:

            <Window x:Class="ListCollectionViewTest.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">
        
                <StackPanel>
                    <DataGrid ItemsSource="{Binding TestList}"
                              RowHeight="22"
                              AutoGenerateColumns="True">
                    </DataGrid>
                    <Button Content="Show All Employees in DB" Click="Button_Click" />
                </StackPanel>        
            </Window>
        

        【讨论】:

          【解决方案4】:

          只需订阅 ObservableCollection 的 CollectionChanged 事件。事件处理程序接收NotifyCollectionChangedEventArgs 类的实例,其中包含一个属性“Action”,描述是否已添加或删除行。它还包含已添加('NewItems')或删除('OldItems')的行列表。这应该为您提供足够的信息来更新您的数据库。

          您可以在行 ViewModel 中实现 INotifyPropertyChanged(我猜是 ItemsList 类),然后订阅它,以查明一行是否脏并需要在数据库中更新。该接口由单个事件 PropertyChanged 组成,只要值发生更改,就会在 ViewModel 的属性设置器中引发该事件。

          您说得对,NotifyCollectionChanged 事件来得太早,无法立即插入数据库。但是您可以在事件处理程序中将该行标记为“已插入”,并在完成该行所需的最后一个属性更改事件(见上文)发生时立即插入它。

          【讨论】:

          • 两个问题; 1)NotifyCollectionChangedAction 只会在您添加新行或删除和现有行时触发,而不是在您修改现有行中的单元格时触发。即无法判断行是否脏。 2) 当您第一次开始在新行中输入时,NotifyCollectionChangedAction.Add 在您有机会填写所有单元格之前被触发。您不能向数据库添加空行,尤其是此时仍有空字段时。所以你必须再次使用更新..我又不知道如何捕获。
          猜你喜欢
          • 1970-01-01
          • 2016-05-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-05
          • 2013-11-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多