WPF:MessageBox是否打破PreviewMouseDown?

时间:2009-02-13 15:38:12

标签: .net wpf events messagebox

我一直在尝试让我的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,它们不会。

这是一个错误还是有什么东西在这里我应该理解?

3 个答案:

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