WPF:MessageBox是否打破PreviewMouseDown?

问题描述 投票:8回答:3

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

这是一个错误还是在这里发生了一些我应该理解的事情?

.net wpf events messagebox
3个回答
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();
}

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);
    }
© www.soinside.com 2019 - 2024. All rights reserved.