WPF: MessageBox нарушает PreviewMouseDown? - PullRequest
8 голосов
/ 13 февраля 2009

Я пытался заставить мое приложение WPF предлагать пользователям либо отменить свои несохраненные изменения, либо отменить их при навигации по TreeView.

Я думаю, что нашел ошибку. MessageBox не работает хорошо с PreviewMouseDown. Кажется, он «обрабатывает» щелчок независимо от того, как установлен его e.Handled, если отображается MessageBox.

Для этого 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 ]

2 голосов
/ 30 марта 2009

У меня точно такая же проблема, и вы правы, полагая, что MessageBox все испортил. Если честно, у меня были другие проблемы с MessageBox при работе с Windows Forms до перехода на WPF. Может быть, это просто какая-то столетняя ошибка, которая стала функцией (как это часто бывает с 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();
}

Как примечание: странно, что Binding всегда помечает мои DataRows как измененные, когда изменяется выбранный элемент в ListBox, у которого ItemsSource привязан к DataTable, (я не знаю, используете ли вы DataTables / Sets) , Чтобы бороться с этим, я отбрасываю любые необработанные изменения, когда выбор уже был изменен (потому что я обрабатываю все, что необходимо в событии MouseDown, которое происходит до этого):

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

И код для обработчика:

private void clearChanges(object sender, SelectionChangedEventArgs e) {
    Data.cancelChanges();
}
0 голосов
/ 21 марта 2019

Окно сообщения / модальное диалоговое окно удалит фокус с выбранного элемента и перенаправленное событие будет отменено После завершения диалогового окна вы можете вызвать событие нажатия мыши на исходном источнике, чтобы завершить событие предварительного просмотра мыши вниз.

    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);
    }
0 голосов
/ 31 марта 2009

Это то, что у меня есть. Это работает, но менее желательно ...

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

Для этого пользователю необходимо нажать «ОК», вручную нажать кнопку «Отменить изменения» (рядом с кнопкой «Сохранить»), нажать другую кнопку «Вы уверены?» окно сообщения, и только после этого снова перемещайтесь по дереву.

...