我的应用程序在关闭时需要保存数据,所以我实现了:
private void oclmEditor_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = false;
OCLMEditorViewModel vm = this.DataContext as OCLMEditorViewModel;
if (vm.SaveModelDataCommand.CanExecute(null))
vm.SaveModelDataCommand.Execute(null);
}
我认为一切都很顺利。但后来我意识到,虽然在关机时保存,但它实际上并非更新源控件首先。这真让我感到惊讶,因为它们被设置为LostFocus
,显然如果它关闭,一切都会失去焦点。
我决定我需要找到一种方法来轻松获取所有控件来更新源代码。根据我的研究,我实施了这些扩展:
public static class Helper
{
public static IEnumerable<DependencyObject> EnumerateVisualChildren(this DependencyObject dependencyObject)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
yield return VisualTreeHelper.GetChild(dependencyObject, i);
}
}
public static IEnumerable<DependencyObject> EnumerateVisualDescendents(this DependencyObject dependencyObject)
{
yield return dependencyObject;
foreach (DependencyObject child in dependencyObject.EnumerateVisualChildren())
{
foreach (DependencyObject descendent in child.EnumerateVisualDescendents())
{
yield return descendent;
}
}
}
public static void UpdateBindingSources(this DependencyObject dependencyObject)
{
foreach (DependencyObject element in dependencyObject.EnumerateVisualDescendents())
{
LocalValueEnumerator localValueEnumerator = element.GetLocalValueEnumerator();
while (localValueEnumerator.MoveNext())
{
BindingExpressionBase bindingExpression = BindingOperations.GetBindingExpressionBase(element, localValueEnumerator.Current.Property);
if (bindingExpression != null)
{
bindingExpression.UpdateSource();
}
}
}
}
}
老实说,我不知道给这个班级最好的名字是什么,也不知道将它存放在应用程序中的位置(我使用了mainwindow.xaml.cs)。
我离题了......所以,我随后更改了关机代码:
private void oclmEditor_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = false;
oclmEditor.UpdateBindingSources();
OCLMEditorViewModel vm = this.DataContext as OCLMEditorViewModel;
if (vm.SaveModelDataCommand.CanExecute(null))
vm.SaveModelDataCommand.Execute(null);
}
原则上它有效。现在,源代码会在保存之前进行更新。太好了!
但我注意到在输出窗口中:
System.Windows.Data错误:8:无法将目标值保存到源。 BindingExpression:路径= SelectedStudentItem;
DataItem ='OCLMEditorViewModel'(HashCode = 32322646); target元素是'DataGrid'(Name ='gridStudents');
target属性是'SelectedItem'(类型'Object')NullReferenceException:'System.NullReferenceException:对象引用未设置为对象的实例。 位于D:\ My Programs \ OCLMEditor \ OCLMEditor \ ViewModels \ OCLMEditorViewModel.cs中的OCLMEditor.OCLMEditorViewModel.set_SelectedStudentItem(学生值):第151行
DataGrid
绑定到CollectionViewSource
。 SelectedItem
绑定到ViewModel
中的属性。我做了更多测试,不得不最终做:
private Student _SelectedStudentItem;
public Student SelectedStudentItem
{
get
{
return _SelectedStudentItem;
}
set
{
// We need to remove this item from the previous student history
if (_SelectedStudentItem != null)
_SelectedStudentItem.History.Remove(Meeting.DateMeeting);
_SelectedStudentItem = value;
if (_SelectedStudentItem == null)
return;
_EditStudentButtonClickCommand.RaiseCanExecuteChanged();
_DeleteStudentButtonClickCommand.RaiseCanExecuteChanged();
OnPropertyChanged("SelectedStudentItem");
if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingMain)
{
_Meeting.TFGW.BibleReadingItem.Main.Name = _SelectedStudentItem.Name;
OnPropertyChanged("BibleReadingMain");
}
else if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingClass1)
{
_Meeting.TFGW.BibleReadingItem.Class1.Name = _SelectedStudentItem.Name;
OnPropertyChanged("BibleReadingClass1");
}
else if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingClass2)
{
_Meeting.TFGW.BibleReadingItem.Class2.Name = _SelectedStudentItem.Name;
OnPropertyChanged("BibleReadingClass2");
}
}
}
我不得不把那个测试放在那里并提前返回。现在异常没有发生。
我是否正确地假设没有其他办法来处理这个问题?我尝试过的一件事是将我的SelectedStudentItem
更改为直接使用我的集合视图CurrentItem
和MoveCurrentTo
方法。但是当用户点击网格行时,我失去了使该变量保持最新的能力。这就是为什么我以前一种方式(绑定到SelectedItem
)。
很抱歉,如果这个问题听起来很冗长或复杂。我不知道如何传达它。