我认为我遗漏了一些简单但我基本上采用多步法获取数据的方法。让我在一个例子中浏览一个更简单的版本。
Observable Collection属于'POCO'类,它是一个简单的POCO类,构成了这两个属性:
PersonID int { get; set; }
Name string { get; set; }
我有一个实体到sql数据模型,它映射了一个在POCO类中包含相同元值的简单数据库表,让我们说简单的例子它有三个行值:
PersonID, Name
1, Brett
2, Emily
3, Test
可观察集合在ModelView中连接如下:
ObservableCollection<POCO> _Pocos;
POCOEntities ee = new POCOEntities();
public ObservableCollection<POCO> POCOs
{
get
{
if (_Pocos == null)
{
List<POCO> mes = this.GetPOCOs();
_Pocos= new ObservableCollection<POCO>(mes);
}
return _Pocos;
}
set
{
_Pocos = value;
OnPropertyChanged("POCOs");
}
}
List<POCO> GetPOCOs()
{
return ee.vPOCO.Select(p => new POCOView()
{
PersonId = p.PersonID,
Name = p.Name
}).ToList();
}
我也有一个当前项目连线。
POCO _CurrentPOCO;
public POCO CurrentPOCO
{
get { return _CurrentPOCO; }
set
{
_CurrentPOCO = value;
OnPropertyChanged("CurrentPOCO");
}
}
4和5是ModelView的内核我将它们连接到datagrid的视图,如下所示:
<DataGrid x:Name="datagrid"
ItemsSource="{Binding POCOs}"
CurrentItem="{Binding CurrentPOCO}" />
这是我没有得到的部分,如何近乎实时地更新数据库的实体模型?该集合连接正常并更新,如何告诉数据库发生了什么?如果我设置了像'CellEditEnding'或'SelectionChanged'这样的事件,并尝试从我的实体模型实现更新proc,那么它将在ModelView中实现BOMBS。如果我只坚持它背后的代码,那么有点,但似乎并没有捕获'后'改变的价值。
即使使用ICommand属性并实现在MVVM中完成的relay命令。这些方法不起作用。所以我很好奇,如果我过度思考它和他们可以烘烤的某种类型的界面,那将为你做清理数据库。我可以处理插入文档,然后使用方法来填充或刷新数据网格,但我希望能够更改datagridview中的值并直接更新数据库。
内容: 以最简单的方式,我只是想更新数据库,因为我更改了datagridview,并且observablecollection发生了变化,因此两者相互同步。
答案 0 :(得分:2)
此处有两类更改:
ObservableCollection
的{{1}}事件,并使用CollectionChanged
和NewItems
属性来确定要添加和/或删除的数据来自DB。OldItems
事件,因为集合本身仍然是相同的。对于#2,我将为POCO类实现一个简单的Viewmodel,用于处理其属性的更新。毕竟,您的POCO应被视为业务对象,不应直接暴露给视图。每个PocoVM都包含对单个POCO实例的引用。
我添加了或多或少我在我的经验中使用的所有代码,除了存根数据库,因为我不知道你在使用什么以及它是如何工作的。只要它返回项目列表并且您可以告诉它更新单个项目,这并不重要。
的 XAML 强> 的
与你的相同,只是我添加了另一个网格(readonly),以便在我的 MysticalDBLayer 接受后显示更改。我也摆脱了CollectionChanged
因为我们将使用CurrentItem
来跟踪我们正在编辑的项目。
PocoVM
查看模型(XAML的DataContext) 这就是这个文件的全部内容。数据库连接可能会根据您使用的内容而有所不同,但基本上我有一个可观察的集合,我以相同的方式填充,除了我为每个POCO 创建一个新的PocoVM(viewmodel)并将新的PocoVM添加到{ {1}}而不是POCO本身。
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock>Input-Grid</TextBlock>
<DataGrid Grid.Row="1"
ItemsSource="{Binding POCOs}"/>
<TextBlock Grid.Row="2">Readonly-Grid</TextBlock>
<DataGrid Grid.Row="3"
ItemsSource="{Binding POCOs, Mode=OneWay}"
IsReadOnly="True"/>
</Grid>
最后是PocoVM
每当您尝试更新其中一个单元格的值时(只有名称将更新:能够使用此代码作为ObservableCollection
只有一个getter),相应的setter将在此类中被调用。在这里,您可以对数据库进行写入,并根据是否成功进行操作。
class VM
{
ObservableCollection<PocoVM> _pocoCollection = new ObservableCollection<PocoVM>();
public ObservableCollection<PocoVM> POCOs
{
get
{
if (_pocoCollection.Count == 0)
{
_pocoCollection = new ObservableCollection<PocoVM>();
IEnumerable<POCO> pocos = MysticalDBLayer.GetItems();
foreach (POCO poco in pocos)
{
_pocoCollection.Add(new PocoVM(poco));
}
}
return _pocoCollection;
}
}
}
答案 1 :(得分:0)
如果我理解正确,您只需要使用 ObservableCollection 的 CollectionChanged 事件。
事件参数包含操作(添加/删除...),您也可以获得 NewItems 和 OldItems 。
因此,您可以跟踪集合上的更改并与数据库进行同步。 我希望我能帮到你。
答案 2 :(得分:0)
创建自己的ObservableCollection
,其覆盖InsertItem()
和RemoveItem()
方法:
public class CustomerCollection : ObservableCollection<Customer>
{
private DataContext _db;
public DataContext Db
{
get { return _db; }
}
public CustomerCollection(IEnumerable<Customer> customers, DataContext context)
: base(customers)
{
_db = context;
}
protected override void InsertItem(int index, Customer item)
{
this.Db.AddToCustomers(item);
this.Db.SaveChanges();
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
this.Db.DeleteObject(this[index]);
this.Db.SaveChanges();
base.RemoveItem(index);
}
}
答案 3 :(得分:-1)
这类似于我刚才在这里回答的一个问题WPF datagrid with MVVM。 (因为我是这个网站的新手,我会复制答案)
您应该使用 ListCollectionView 。
以下是展示如何操作的示例:
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>