WPF:MessageBox会影响PreviewMouseDown事件吗?

8
我一直在尝试让我的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("测试", "测试", MessageBoxButton.OK) e.Handled = False End Sub

这两种方法的行为不同。没有消息框时,TreeViewNodes_Selected() 或者 TreeViewThings_Expanded() 将会执行。有了消息框,它们就不会执行。

这是一个错误还是有什么我应该理解的问题?

3个回答

2
我遇到了完全相同的问题,你所想的MessageBox搞砸了一切。说实话,在切换到WPF之前,在使用Windows Forms时我还遇到过其他MessageBox问题。也许这只是一个世纪老虫子变成了功能(通常是Microsoft的做法)?
无论如何,我能提供给你的唯一解决方案就是对我有用的方案。我在使用ListBox时遇到了类似的问题——如果表单中的数据发生更改,当ListBox的选择发生更改时(通过单击新项目或使用“向上”或“向下”键),我会在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中选定的项更改时(如果您使用DataTables / Sets我不知道),Binding总是将我的DataRows标记为已修改。为了解决这个问题,一旦选择已经被更改(因为我在先前发生的MouseDown事件中处理任何必要的内容),我会丢弃任何未处理的更改:
<ListBox IsSynchronizedWithCurrentItem="True" [...] SelectionChanged="clearChanges"> ... </ListBox>

下面是处理程序的代码:

private void clearChanges(object sender, SelectionChangedEventArgs e) {
    Data.cancelChanges();
}

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

这需要用户点击“确定”按钮,手动点击“放弃更改”按钮(靠近“保存”按钮),点击另一个“你确定吗?”的消息框,再次浏览树形结构。


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);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接