Kyl*_*Ren 4 c# wpf xaml datagrid mvvm
我已经搜索并来到了一堵砖墙。关于如何做到这一点似乎有很多问题和答案,但我找不到任何我可以具体实施的东西(显然我的理解有问题)。
我希望能够更新几个 Datagrids 并脱离你不应该命名你的控件的前提,我不知道如何让它工作。
所以到目前为止我能够想出的是使用System.Windows.Interactivity程序集。但我不知道如何实现背后的代码(我当然可以展示我试图让它工作的所有代码,但不幸的是它只会使帖子变得混乱,所以我不包括它)。我尽可能多地研究实施ICommand.
所以我有 XAML:
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowEditEnding">
<i:InvokeCommandAction Command="{Binding CanExecuteChanged}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)
但我似乎无法获得背后的代码,以便能够在RowEditEnding完成时通知并能够使用新数据更新数据库。
因此,考虑到 MVVM 模型,我该如何触发事件以便更新数据库?
Bra*_*mer 10
EDIT2:将 People 改为 ObservableCollection 而不是 List。添加了 CollectionChanged 事件以处理从集合中的 Person 对象附加/删除 PropertyChanged 事件。
编辑:为了一致性在 ViewModel 中更改了 foreach。
首先,Model-View-ViewModel(MVVM) 意味着你应该有尽可能少的代码,实际上最好没有。相反,UI 的逻辑应该在 xaml(视图)中完成,而数据的逻辑应该在模型中完成,并将数据组织成可呈现的形式应该通过视图模型完成,这是一个单独的文件对 WPF 或 UI 一无所知。
您似乎也对数据绑定的工作方式有误解。您指的是您在后面的代码中所做的事情,但绑定表达式通常指向您的视图上的属性DataContext,在 MVVM 中应将其设置为您的 ViewModel。这是一个很好的教程在这里,可以让你开始结合。我还推荐了该帖子的后续帖子,当我开始使用 WPF 时,它们对我帮助很大。
现在来看看 DataGrid 的情况。首先,这里有一个关于 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>
Run Code Online (Sandbox Code Playgroud)
后面的代码:
namespace TestWPFApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,后面的代码几乎是空的。只是默认代码,加上DataContext = new MyViewModel();. 正如我之前提到的,您的视图的 DataContext 应该是您的视图模型。
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.
}
}
Run Code Online (Sandbox Code Playgroud)
List<Person>我的视图模型中有一个 type 属性。 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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这里要注意的重要一点是INotifyPropertyChanged,这个接口通常对 MVVM 和 WPF 数据绑定非常重要。如果实施得当,它会导致对象在PropertyChanged其属性之一发生更改时发布事件。这会告诉任何绑定的 WPF 控件它们应该获取新值,并且还允许您的 ViewModel 监视它们的更改。因此,在视图模型中,我们将事件处理程序附加到CollectionChangedPeople上的事件,然后负责PropertyChanged为添加到集合中的每个项目附加事件处理程序。
CollectionChanged每当在集合中添加、删除或替换项目时,都会调用该事件,并将PropertyChanged从旧项目中删除处理程序并将处理程序添加到新项目中。重要的是要记住删除处理程序,否则从集合中删除的项目可能不会被正确地垃圾收集。
person_PropertyChanged每次Person对象之一的属性更改时都会调用该方法。在person_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.
}
Run Code Online (Sandbox Code Playgroud)
我上面显示的网格中的每一行代表一个人对象。每当用户更改网格中某个单元格的Person值时,该行所代表的对象的相应属性也将被更新,这将触发一个PropertyChanged事件,并调用person_PropertyChanged.
假设用户将Age“Bob”的列更改为 37。在用户点击 Enter 或移出单元格后,代表“Bob”Age的Person对象的 Age 属性将从 45 更改为 37。这将导致该Person对象升高PropertyChanged,这将调用person_PropertyChanged的方法MyViewModel。 person_PropertyChanged然后将调用SaveData哪个是您将代码保存到数据库的更新的 Person 行的位置。
如果您有任何问题,请告诉我!
| 归档时间: |
|
| 查看次数: |
5669 次 |
| 最近记录: |