我已经搜查并且已经到了一堵砖墙。关于如何做到这一点似乎有很多问题和答案,但是我无法找到具体的我可以实现的任何内容(显然是我理解的问题)。
我希望能够更新多个Datagrids,并且假设您不应该为控件命名,我很想知道如何让它工作。
所以到目前为止我能够提出的是使用System.Windows.Interactivity
程序集。但我不知道如何实现后面的代码(我当然可以显示我试图让它工作的所有代码,但不幸的是它只会使帖子混乱,所以我不包括它)。我尽可能多地研究实施ICommand
。
所以我有XAML:
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowEditEnding">
<i:InvokeCommandAction Command="{Binding CanExecuteChanged}" />
</i:EventTrigger>
</i:Interaction.Triggers>
但我似乎无法获得代码,以便能够在RowEditEnding
完成时通知并能够使用新数据更新数据库。
因此,考虑到MVVM模型,我如何才能触发事件以便更新数据库?
答案 0 :(得分:3)
EDIT2:将人员更改为ObservableCollection而不是List。添加了CollectionChanged事件以处理从集合中的Person对象附加/删除PropertyChanged事件。
编辑:在ViewModel中更改了foreach以保持一致性。
首先,Model-View-ViewModel(MVVM)意味着您应该尽可能少地使用代码,实际上最好不使用。相反,UI的逻辑应该在xaml(视图)中完成,而数据的逻辑应该在模型中完成,并且数据组织成可呈现的形式应该通过视图模型完成,视图模型是一个单独的文件,对WPF或用户界面一无所知。
您似乎对数据绑定的工作方式存在误解。您指的是您在代码中所做的事情,但绑定表达式通常指向视图的DataContext
上的属性,MVVM中的属性应设置为您的ViewModel。有一个很好的教程here可以帮助您开始绑定。我还推荐了那个帖子的后续帖子,当我开始使用WPF时,他们给了我很多帮助。
现在了解DataGrid的情况。首先,here是WPF DataGrid的一个很好的教程。 接下来,您声明要在更新行时更新数据库。以下是如何以MVVM样式执行此操作的示例:
假设您有一个像这样的DataGrid视图:
<UserControl x:Class="MyProject.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid ItemsSource="{Binding People, Mode=OneWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
<DataGridTextColumn Header="Age" Binding="{Binding Age}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
代码背后:
namespace TestWPFApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
}
请注意,后面的代码几乎是空的。只是默认代码,加上DataContext = new MyViewModel();
。正如我之前提到的,视图的DataContext应该是您的View Model。
MyViewModel
看起来像这样:
public class MyViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged Impl
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
private ObservableCollection<Person> m_people;
public ObservableCollection<Person> People
{
get { return m_people; }
private set
{
if (value == m_people)
return;
m_people = value;
OnPropertyChanged();
}
}
public MyViewModel()
{
m_people = new ObservableCollection<Person>();
m_people.CollectionChanged += m_people_CollectionChanged;
m_people.Add(new Person() { FirstName = "Bob", LastName = "Brown", Age = 45 });
m_people.Add(new Person() { FirstName = "Sarah", LastName = "Smith", Age = 25 });
}
private void m_people_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null && e.NewItems.Count > 0)
{
foreach (INotifyPropertyChanged item in e.NewItems.OfType<INotifyPropertyChanged>())
{
item.PropertyChanged += people_PropertyChanged;
}
}
if (e.OldItems != null && e.OldItems.Count > 0)
{
foreach (INotifyPropertyChanged item in e.OldItems.OfType<INotifyPropertyChanged>())
{
item.PropertyChanged -= people_PropertyChanged;
}
}
}
//Property Changed will be called whenever a property of one of the 'Person'
//objects is changed.
private void person_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var row = sender as Person;
SaveData(row);
}
private void SaveData(Person row)
{
//Save the row to the database here.
}
}
我的视图模型中有List<Person>
类型的属性。 Person
看起来像这样:
public class Person : INotifyPropertyChanged
{
#region INotifyPropertyChanged Impl
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
private string m_firstName;
public string FirstName
{
get { return m_firstName; }
set
{
if (value == m_firstName)
return;
m_firstName = value;
OnPropertyChanged();
}
}
private string m_lastName;
public string LastName
{
get { return m_lastName; }
set
{
if (value == m_lastName)
return;
m_lastName = value;
OnPropertyChanged();
}
}
private int m_age;
public int Age
{
get { return m_age; }
set
{
if (value == m_age)
return;
m_age = value;
OnPropertyChanged();
}
}
}
这里要注意的重要一点是 INotifyPropertyChanged ,这个界面对MVVM和WPF数据绑定一般非常重要。正确实现后,只要其中一个属性发生更改,就会导致对象发布PropertyChanged
事件。这告诉任何绑定的WPF控件它们应该获取新值,并且还允许ViewModel监视它们的更改。因此,在视图模型中,我们将事件处理程序附加到People上的CollectionChanged
事件,然后为添加到集合中的每个项目附加PropertyChanged
事件处理程序。
只要在集合中添加,删除或替换项目,就会调用CollectionChanged
事件,并从旧项目中删除PropertyChanged
处理程序,并将处理程序添加到新项目中。重要的是要记住删除处理程序,或者从集合中删除的项目可能无法正确地进行垃圾回收。
每次person_PropertyChanged
个对象的属性发生更改时,都会调用Person
方法。在person_PropertyChanged
中,我们然后调用方法来更新数据库,传递更新的行(在本例中为Person),如下所示:
//Property Changed will be called whenever a property of one of the 'Person'
//objects is changed.
private void person_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var row = sender as Person;
SaveData(row);
}
private void SaveData(Person row)
{
//Save the row to the database here.
}
上面显示的网格中的每一行代表一个人物对象。每当用户更改网格中某个单元格的值时,该行所代表的Person
对象的相应属性也将更新,这将触发PropertyChanged
事件,并调用{ {1}}。
假设用户更改了&#34; Bob&#34;的person_PropertyChanged
列。用户点击进入或离开单元格Age
表示&#34; Bob&#34;将从45更改为37.这将导致Age
对象引发Person
,这将调用Person
中的PropertyChanged
方法。然后person_PropertyChanged
将调用MyViewModel
,您可以将代码保存在更新的Person行中。
如果您有任何疑问,请与我们联系!