在WPF中捕获对绑定XML的更改的简单位置
我已经将一个XML结构绑定到WPF表单,并将其全部设置为只需按一个按钮即可将更改提交到数据库 我正在寻找一种方法来检测用户是否更改了模型中的任何内容,以知道如何启用“保存”按钮,将表单设置为“脏”等。我更喜欢数据方面的内容,因为XAML视图绑定干净,基本上没有逻辑,因此ViewModel相当缺乏实质性,所以我想指出模型处于需要提交到数据库的状态在WPF中捕获对绑定XML的更改的简单位置,wpf,xml,mvvm,binding,Wpf,Xml,Mvvm,Binding,我已经将一个XML结构绑定到WPF表单,并将其全部设置为只需按一个按钮即可将更改提交到数据库 我正在寻找一种方法来检测用户是否更改了模型中的任何内容,以知道如何启用“保存”按钮,将表单设置为“脏”等。我更喜欢数据方面的内容,因为XAML视图绑定干净,基本上没有逻辑,因此ViewModel相当缺乏实质性,所以我想指出模型处于需要提交到数据库的状态 我考虑过的一个“黑客”是在加载时捕获XML,然后与DataContext的副本进行简单比较,以确定表单是否脏。如果XML包含在可以使用的XDocumen
我考虑过的一个“黑客”是在加载时捕获XML,然后与DataContext的副本进行简单比较,以确定表单是否脏。如果XML包含在可以使用的XDocument中
XmlDocument类具有您可以注册的属性。创建如下视图模型:
public class XmlDataViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
{
h(this, new PropertyChangedEventArgs(propertyName));
}
}
private XmlDocument _XmlData;
public XmlDocument XmlData
{
get { return _XmlData; }
set
{
if (value != _XmlData)
{
if (_XmlData != null)
{
// it's not likely you'll need this, but why take chances?
_XmlData.NodeChanged -= XmlData_NodeChanged;
}
_XmlData = value;
_XmlData.NodeChanged += XmlData_NodeChanged;
CanSave = false;
Provider = new XmlDataProvider { Document = XmlData };
OnPropertyChanged("Provider");
}
}
}
private void XmlData_NodeChanged(object sender, XmlNodeChangedEventArgs e)
{
CanSave = true;
}
public XmlDataProvider Provider { get; private set; }
public RelayCommand SaveCommand
{
get
{
return new RelayCommand(x => Save(), x => CanSave);
}
}
private bool CanSave { get; set; }
private void Save() { }
}
<StackPanel DataContext="{Binding Provider}">
<TextBox Text="{Binding XPath=/Data/Field1}"/>
<TextBox Text="{Binding XPath=/Data/Field2}"/>
</StackPanel>
将视图的DataContext
设置为此对象的实例,并像这样绑定控件:
public class XmlDataViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
{
h(this, new PropertyChangedEventArgs(propertyName));
}
}
private XmlDocument _XmlData;
public XmlDocument XmlData
{
get { return _XmlData; }
set
{
if (value != _XmlData)
{
if (_XmlData != null)
{
// it's not likely you'll need this, but why take chances?
_XmlData.NodeChanged -= XmlData_NodeChanged;
}
_XmlData = value;
_XmlData.NodeChanged += XmlData_NodeChanged;
CanSave = false;
Provider = new XmlDataProvider { Document = XmlData };
OnPropertyChanged("Provider");
}
}
}
private void XmlData_NodeChanged(object sender, XmlNodeChangedEventArgs e)
{
CanSave = true;
}
public XmlDataProvider Provider { get; private set; }
public RelayCommand SaveCommand
{
get
{
return new RelayCommand(x => Save(), x => CanSave);
}
}
private bool CanSave { get; set; }
private void Save() { }
}
<StackPanel DataContext="{Binding Provider}">
<TextBox Text="{Binding XPath=/Data/Field1}"/>
<TextBox Text="{Binding XPath=/Data/Field2}"/>
</StackPanel>
将按钮(或任何内容)绑定到SaveCommand
当您将XmlData
属性设置为XmlDocument
(您可以在绑定到XmlDataViewModel
之前或之后执行此操作)时,它将创建一个新的XmlDataProvider
并引发属性更改
,因此视图的控件将全部刷新,数据将按照您的预期被推出。对绑定控件的更改将引发NodeChanged
,这将设置CanSave
,从而启用SaveCommand
如果随后将XmlData
设置为不同的XmlDocument
,则绑定的控件将刷新,并且SaveCommand
将被禁用,直到用户更改新XmlDocument
中的数据。并且之前的XmlDocument
的NodeChanged
事件将被取消注册,以便可以释放该对象
我得说,这是一个非常复杂的行为,因为实际上只有很少的代码。谢谢你提出这个问题。看起来就是这样。当我附加该事件时,您知道吗,因为目前似乎找不到在绑定后添加该事件的方法,例如,当表单最初加载时,该事件多次激发。我尝试了.Loaded(它是一个wpf树视图),但没有成功。通过创建一个特定的调用来加载XDocument,然后添加EventHandler,而不是直接从start/constructor加载xml。还是我遗漏了什么?不@Erno-我想我是那个遗漏了什么的人。在我看来,有东西在完成绘制之前触发了XMLNodeChanged事件。无法理解如何/为什么,但必须是一个绑定的东西。谢谢@Robert-我已经实现了这一点,而且它似乎工作得很好,尽管我的XAML视图中的某些东西必须在它绘制XML时更改我的XML,因为它在绘制时触发XMLNodeChanged事件。我认为这也是@Erno回答的问题。我尝试了他的方法,得到了类似的结果;到XmlData_NodeChanged事件处理程序,以便通知UI CanSave已更改并知道要更新,当然,我必须跟踪RelayCommand的实现(很简单,但如果有人需要的话。最终解决了问题。当绑定的组合框绑定到ItemSource中不存在的字段时,NodeChanged正在启动。在eventhandler中捕获并忽略该条件完成了此解决方案,非常感谢。您不必在
CanSave
上实现更改通知。PropertyChanged
事件与启用/禁用命令无关。查看CommandManager.RequerySuggested
和ICommand.CanExecuteChanged
。