2009-02-13 7 views
8

He intentado que mi aplicación WPF solicite a los usuarios descartar sus cambios no guardados o cancelar cuando naveguen utilizando TreeView.WPF: ¿MessageBox Break PreviewMouseDown?

Creo que he encontrado un fallo. El MessageBox no funciona bien con PreviewMouseDown. Parece que "maneja" un clic independientemente de cómo se configure e.Handled si se muestra un MessageBox.

Por esta XAML ...

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

... comparar estos métodos alternativos ...

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

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

Estos dos métodos se comportan de manera diferente. Sin MessageBox, se ejecutará TreeViewNodes_Selected() o TreeViewThings_Expanded(). Con el MessageBox, no lo harán.

¿Esto es un error o hay algo aquí que debería entender?

Respuesta

2

Tengo exactamente el mismo problema y tienes razón al pensar que MessageBox está arruinando las cosas. Para ser sincero, he tenido otros problemas con MessageBox mientras trabajaba con Windows Forms antes de cambiar a WPF. Tal vez es solo un error centenario que se convirtió en una característica (como suele suceder con Microsoft).

En cualquier caso, la única solución que puedo ofrecerte es la que me ha funcionado. Estaba teniendo problemas para hacer que una situación similar funcione con un ListBox, si hubo cambios en los datos del formulario, cuando la selección del ListBox cambió (haciendo clic en un elemento nuevo o usando las teclas "Arriba" o "Abajo"), Ofrecí al usuario una opción en el MessageBox ya sea para guardar, descartar o cancelar.

Naturalmente, utilizar el enfoque directo para manejar los eventos MouseDown o PreviewMouseDown de ListBox no funcionó bien con un MessageBox. Esto es lo que funcionó.

que tienen una plantilla de datos para mostrar los elementos en mi cuadro de lista (estoy casi te esperando tener la misma):

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

Nota cómo he moví los controladores de eventos KeyDown y MouseDown a la Control TextBlock en su lugar. Me quedé con el mismo código subyacente:

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

Como nota al margen, que es extraño cómo encuadernación siempre marca mi DataRows, modificadas cuando el elemento seleccionado en el cuadro de lista, que tiene ItemsSource unido a un DataTable, los cambios (I Don no sé si está usando DataTables/Sets). Para combatir esto, descarto cualquier cambio no controladas una vez que la selección ya ha sido cambiado (porque yo manejo todo lo que es necesario en el evento MouseDown que se produce antes de que):

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

Y el código subyacente para el controlador:

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

Esto es lo que tengo. Funciona, pero es menos deseable ...

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 

Esto requiere que el usuario haga clic en "Aceptar", haga clic en un botón manualmente "Descartar cambios" (cerca del botón "Guardar"), haga clic a través de otro "¿Seguro?" cuadro de mensaje, y solo luego navegar con el árbol nuevamente.