8

我一直在尝试让我的 WPF 应用程序提示用户放弃未保存的更改或在他们使用 TreeView 导航时取消。

我想我发现了一个错误。MessageBox 不能很好地与 PreviewMouseDown 配合使用。如果显示了 MessageBox,则无论其 e.Handled 是如何设置的,它似乎都会“处理”一次点击。

对于这个 XAML...

<TreeView Name="TreeViewThings"
    ...
    PreviewMouseDown="TreeViewThings_PreviewMouseDown"
    TreeViewItem.Expanded="TreeViewThings_Expanded"
    TreeViewItem.Selected="TreeViewThings_Selected" >

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

子 TreeViewNodes_PreviewMouseDown(...)
    e.Handled = False
结束子

子 TreeViewNodes_PreviewMouseDown(...)
    MessageBox.Show("Test", "Test", MessageBoxButton.OK)
    e.Handled = False
结束子

这两种方法的行为不同。没有MessageBox,TreeViewNodes_Selected()否则TreeViewThings_Expanded()会执行。使用 MessageBox,他们不会。

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

4

3 回答 3

2

I'm having precisely the same problem and you're right in thinking that MessageBox is screwing things up. To be honest, I've had other issues with MessageBox while working with Windows Forms before switching to WPF. Maybe it's just some century-old bug that became a feature (as often it is with Microsoft)?

In any case, the only solution I can offer you is the one that has worked for me. I was having problems with getting a similar situation to work with a ListBox - if there were changes to data in the form, when selection of the ListBox changed (either by clicking on new item or using keys "Up" or "Down"), I offered user a choice in the MessageBox whether to save, discard or cancel.

Naturally using the direct approach of handling ListBox's MouseDown or PreviewMouseDown events didn't work well with a MessageBox. Here's what worked.

I have a data template to display items in my ListBox (I'm almost expecting you to have the same):

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Path=NAME}" KeyDown="checkForChanges" MouseDown="checkForChanges"/>
    </DataTemplate>
</ListBox.ItemTemplate>

Note how I've moved the KeyDown and MouseDown event handlers to the TextBlock control instead. I kept the same code-behind:

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

As a side note, it's odd how Binding always marks my DataRows as Modified when the selected item in the ListBox, which has ItemsSource bound to a DataTable, changes (I don't know if you're using DataTables/Sets). To battle that, I discard any unhandled changes once the selection has already been changed (because I handle anything that's necessary in the event MouseDown that occurs prior to that):

<ListBox IsSynchronizedWithCurrentItem="True" [...] SelectionChanged="clearChanges"> ... </ListBox>

And the code-behind for the handler:

private void clearChanges(object sender, SelectionChangedEventArgs e) {
    Data.cancelChanges();
}
于 2009-03-30T19:41:32.723 回答
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

这需要用户点击“OK”,手动点击一个“Discard Changes”按钮(靠近“Save”按钮),点击另一个“Are you sure?” 消息框,然后才再次使用树导航。

于 2009-03-30T22:44:37.103 回答
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);
    }
于 2019-03-21T14:57:39.807 回答