2009-02-13 4 views
8

J'ai essayé d'obtenir mon application WPF pour inviter les utilisateurs à ignorer leurs modifications non enregistrées ou à annuler quand ils naviguent en utilisant un TreeView.WPF: MessageBox Break PreviewMouseDown?

Je pense que je l'ai trouvé un bug. Le MessageBox ne joue pas bien avec PreviewMouseDown. Il semble "gérer" un clic indépendamment de la façon dont son e.Handled est défini s'il y a un MessageBox affiché.

Pour cette XAML ...

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

... comparer ces méthodes alternatives ...

 
Sub TreeViewNodes_PreviewMouseDown(...) 
    e.Handled = False 
End Sub 

Sub TreeViewNodes_PreviewMouseDown(...) 
    MessageBox.Show("Test", "Test", MessageBoxButton.OK) 
    e.Handled = False 
End Sub 

Ces deux méthodes se comportent différemment. Sans le MessageBox, TreeViewNodes_Selected() ou TreeViewThings_Expanded() va s'exécuter. Avec le MessageBox, ils ne le feront pas.

Est-ce un bug ou y a-t-il quelque chose que je devrais comprendre?

Répondre

2

J'ai exactement le même problème et vous avez raison de penser que MessageBox est en train de tout bousiller. Pour être honnête, j'ai eu d'autres problèmes avec MessageBox tout en travaillant avec Windows Forms avant de passer à WPF. Peut-être que c'est juste un bug centenaire qui est devenu une fonctionnalité (comme souvent avec Microsoft)?

Dans tous les cas, la seule solution que je peux vous offrir est celle qui a fonctionné pour moi. J'avais des problèmes avec une situation similaire à travailler avec un ListBox - s'il y avait des changements aux données dans le formulaire, quand la sélection de la ListBox a changé (soit en cliquant sur nouvel élément ou en utilisant les clés "Up" ou "Down") J'ai offert à l'utilisateur un choix dans le MessageBox, qu'il s'agisse de sauvegarder, de rejeter ou d'annuler.

L'utilisation directe de l'approche directe de gestion des événements MouseDown ou PreviewMouseDown de ListBox ne fonctionnait pas correctement avec un MessageBox. Voici ce qui a fonctionné.

J'ai un modèle de données pour afficher les éléments dans mon ListBox (je suis presque vous attend d'avoir la même):

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

Notez que j'ai déplacé les gestionnaires d'événements KeyDown et MouseDown au Contrôle TextBlock à la place. J'ai gardé le même 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(); 
} 

Comme une note de côté, il est étrange caractère contraignant marque toujours mes DataRows tel que modifié lorsque l'élément sélectionné dans la zone de liste, qui a ItemsSource lié à un DataTable, les changements (je don ne sais pas si vous utilisez DataTables/Sets). Pour combattre, j'annuler tout changement non gérées une fois que la sélection a déjà été changé (parce que je gère tout ce qui est nécessaire en cas MouseDown qui se produit avant que):

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

Et le code-behind pour le gestionnaire:

private void clearChanges(object sender, SelectionChangedEventArgs e) { 
    Data.cancelChanges(); 
} 
0

C'est ce que j'ai. Cela fonctionne, mais est moins souhaitable ...

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 

Cela demande à l'utilisateur de cliquer sur « OK », cliquez sur manuellement un bouton « Supprimer les modifications » (près du bouton « Enregistrer »), cliquer sur une autre « Êtes-vous sûr? » boîte de message, et seulement ensuite naviguer à nouveau avec l'arbre.