WPF:MessageBox是否打破PreviewMouseDown?

Zac*_*son 8 .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" >
Run Code Online (Sandbox Code Playgroud)

...比较这些替代方法......

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,他们不会.

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

Ale*_*dra 2

我遇到了完全相同的问题,你认为 MessageBox 把事情搞砸了,这是正确的。老实说,在切换到 WPF 之前,我在使用 Windows 窗体时还遇到了 MessageBox 的其他问题。也许这只是一些百年历史的错误变成了一项功能(就像微软经常发生的那样)?

无论如何,我能为您提供的唯一解决方案就是对我有用的解决方案。我在使用列表框时遇到类似的情况 - 如果表单中的数据发生更改,当列表框的选择发生变化时(通过单击新项目或使用“向上”或“向下”键),我在消息框中为用户提供了是否保存、丢弃或取消的选择。

当然,使用处理 ListBox 的 MouseDown 或 PreviewMouseDown 事件的直接方法对于 MessageBox 来说效果不佳。这是有效的。

我有一个数据模板来显示列表框中的项目(我几乎希望您也有相同的):

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Path=NAME}" KeyDown="checkForChanges" MouseDown="checkForChanges"/>
    </DataTemplate>
</ListBox.ItemTemplate>
Run Code Online (Sandbox Code Playgroud)

请注意我如何将 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();
}
Run Code Online (Sandbox Code Playgroud)

附带说明一下,当 ListBox 中的 ItemsSource 绑定到 DataTable 中的所选项目发生更改(我不知道您是否使用 DataTables/Sets)时,Binding 总是将我的 DataRows 标记为“已修改”,这很奇怪。为了解决这个问题,一旦选择已经更改,我就会丢弃所有未处理的更改(因为我处理了在此之前发生的 MouseDown 事件中所需的任何内容):

<ListBox IsSynchronizedWithCurrentItem="True" [...] SelectionChanged="clearChanges"> ... </ListBox>
Run Code Online (Sandbox Code Playgroud)

以及处理程序的隐藏代码:

private void clearChanges(object sender, SelectionChangedEventArgs e) {
    Data.cancelChanges();
}
Run Code Online (Sandbox Code Playgroud)