我一直在尝试让我的WPF应用程序提示用户丢弃未保存的更改,或者在使用TreeView导航时取消。
我想我发现了一个错误。 MessageBox与PreviewMouseDown不兼容。它似乎“处理”一个点击,无论如何显示一个MessageBox,它的e.Handled是如何设置的。
对于这个XAML ......
<TreeView Name="TreeViewThings"
...
PreviewMouseDown="TreeViewThings_PreviewMouseDown"
TreeViewItem.Expanded="TreeViewThings_Expanded"
TreeViewItem.Selected="TreeViewThings_Selected" >
...比较这些替代方法......
Sub TreeViewNodes_PreviewMouseDown(...) e.Handled = False End Sub Sub TreeViewNodes_PreviewMouseDown(...) MessageBox.Show("Test", "Test", MessageBoxButton.OK) e.Handled = False End Sub
这两种方法表现不同。如果没有MessageBox,TreeViewNodes_Selected()
或TreeViewThings_Expanded()
将会执行。使用MessageBox,它们不会。
这是一个错误还是有什么东西在这里我应该理解?
答案 0 :(得分:2)
我遇到了完全相同的问题,你认为MessageBox搞砸了。老实说,在切换到WPF之前,我在使用Windows Forms时遇到了MessageBox的其他问题。也许这只是一个百年历史的错误,成为一个功能(通常是微软)?
无论如何,我能为您提供的唯一解决方案就是为我工作的解决方案。我遇到了类似情况与ListBox一起工作的问题 - 如果表单中的数据发生了变化,当ListBox的选择发生变化时(通过点击新项目或使用“Up”或“Down”键),我在MessageBox中为用户提供了一个选择,即保存,丢弃还是取消。
自然地使用处理ListBox的MouseDown或PreviewMouseDown事件的直接方法对MessageBox不起作用。这是有效的。
我有一个数据模板来显示我的ListBox中的项目(我几乎希望你有相同的内容):
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=NAME}" KeyDown="checkForChanges" MouseDown="checkForChanges"/>
</DataTemplate>
</ListBox.ItemTemplate>
请注意我是如何将KeyDown和MouseDown事件处理程序移动到TextBlock控件。我保持相同的代码隐藏:
// The KeyDown handler
private void checkForChanges(object sender, KeyEventArgs e) {
e.Handled = checkForChanges();
}
// Method that checks if there are changes to be saved or discard or cancel
private bool checkForChanges() {
if (Data.HasChanges()) {
MessageBoxResult answer = MessageBox.Show("There are unsaved changes. Would you like to save changes now?", "WARNING", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
if (answer == MessageBoxResult.Yes) {
Data.AcceptDataChanges();
} else if (answer == MessageBoxResult.Cancel) {
return true;
}
return false;
}
return false;
}
// The MouseDown handler
private void checkForChanges(object sender, MouseButtonEventArgs e) {
e.Handled = checkForChanges();
}
作为旁注,奇怪的是,当ListBox中的选定项目(其中ItemsSource绑定到DataTable)发生更改时,Binding始终将我的DataRows标记为已修改(我不知道您是否正在使用DataTables / Sets) 。为了解决这个问题,一旦选择已经改变,我就会丢弃任何未处理的更改(因为我处理了之前发生的MouseDown事件中所需的任何事情):
<ListBox IsSynchronizedWithCurrentItem="True" [...] SelectionChanged="clearChanges"> ... </ListBox>
处理程序的代码隐藏:
private void clearChanges(object sender, SelectionChangedEventArgs e) {
Data.cancelChanges();
}
答案 1 :(得分:0)
这就是我所拥有的。它有效,但不太可取......
Sub TreeViewNodes_PreviewMouseDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
If UnsavedChangesExist() Then
MessageBox.Show("You have unsaved changes.", "Unsaved Changes", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK)
e.Handled = True
End If
End Sub
这要求用户点击“确定”,手动点击“放弃更改”按钮(靠近“保存”按钮),点击另一个“你确定吗?”消息框,然后再次使用树导航。
答案 2 :(得分:0)
消息框/模式对话框将从所选项目中移出焦点,并且路由事件被取消。对话框完成后,您可以在原始源上引发鼠标按下事件以完成原始预览鼠标按下事件。
private void PreviewMouseDown(MouseButtonEventArgs obj)
{
var dialogResult = MessageBox.Show("Do you want to save your changes?", "Pending Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
if (dialogResult == MessageBoxResult.Cancel) return;
// Yes / No was selected.
var source = (UIElement) obj.OriginalSource;
var args = new MouseButtonEventArgs(obj.MouseDevice, obj.Timestamp, obj.ChangedButton) {RoutedEvent = UIElement.MouseDownEvent};
source.RaiseEvent(args);
}