Mi sto davvero grattando la testa con questo. Ho una finestra principale che apre una finestra di dialogo. Dopo la chiusura della finestra di dialogo, il metodo CanExecute sui comandi associati nella finestra di dialogo è ancora in esecuzione. Ciò sta causando alcuni seri problemi nella mia applicazione.Quando si separa l'ui dai comandi?
Esempio:
MainWindow ha un pulsante con un gestore di clic. Questo è il gestore di eventi click:
private void Button_Click(object sender, RoutedEventArgs e)
{
DialogWindow window = new DialogWindow();
window.ShowDialog();
}
Nella finestra mi legano un elementi di controllo a una risorsa statica nella finestra di dialogo, e ogni elemento della lista ha un comando:
<Window.Resources>
<Collections:ArrayList x:Key="itemsSource">
<local:ItemViewModel Description="A"></local:ItemViewModel>
<local:ItemViewModel Description="B"></local:ItemViewModel>
<local:ItemViewModel Description="C"></local:ItemViewModel>
</Collections:ArrayList>
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<Button Grid.Column="1" Command="{Binding Path=CommandClickMe}" Content="{Binding Path=Description}" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
</Button>
</DataTemplate>
</Window.Resources>
<Grid>
<ToolBar ItemsSource="{StaticResource itemsSource}"></ToolBar>
</Grid>
Si tratta di ViewModel:
public class ItemViewModel
{
private RelayWpfCommand<object> _commandClickMe;
public RelayWpfCommand<object> CommandClickMe
{
get
{
if (_commandClickMe == null)
_commandClickMe = new RelayWpfCommand<object>(obj => System.Console.Out.WriteLine("Hei mom"), obj => CanClickMe());
return _commandClickMe;
}
}
private bool CanClickMe()
{
return true;
}
public string Description { get; set; }
E questo è l'implementazione DelegateCommand:
public class RelayWpfCommand<T> : ICommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public RelayWpfCommand(Action<T> execute, Predicate<T> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
/// <summary>
/// Forces a notification that the CanExecute state has changed
/// </summary>
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
public bool CanExecute(T parameter)
{
return _canExecute(parameter);
}
public void Execute(T parameter)
{
_execute(parameter);
}
bool ICommand.CanExecute(object parameter)
{
if (!IsParameterValidType(parameter))
return false;
return CanExecute((T)parameter);
}
void ICommand.Execute(object parameter)
{
if (!IsParameterValidType(parameter))
throw new ArgumentException(string.Format("Parameter must be of type {0}", typeof(T)));
Execute((T)parameter);
}
private static bool IsParameterValidType(object parameter)
{
if (parameter != null && !typeof(T).IsAssignableFrom(parameter.GetType()))
return false;
return true;
}
}
Ora, se chiudo la finestra di dialogo e imposto un punto di interruzione nel metodo CanExecute (sto usando Prism DelegateCommand con iscrizione evento debole) sul viewmodel, noto che si attiva anche se la finestra di dialogo è stata chiusa. Perché mai il collegamento tra il pulsante nella finestra di dialogo e il comando sul ViewModel è ancora attivo?
E sto verificando se viene eseguito chiudendo la finestra e in un secondo momento impostando un punto di interruzione nel metodo "CanClickMe" nel viewmodel. Verrà eseguito per un po ', quindi improvvisamente si fermerà (probabilmente a causa di GC). Questo comportamento non deterministico sta causando problemi perché nell'applicazione reale il viewmodel potrebbe già essere disposto.
A che punto vedi questo? L'istanza della finestra sarà ancora inclusa dopo la chiusura, finché non si abbandona l'evento Click. Questo per consentire al chiamante di accedere alle proprietà nella finestra (si pensi, ad esempio, a una finestra Opzioni). Inoltre, cosa c'è nel CanExecute sta causando un problema? Il problema potrebbe essere in realtà che stai creando effetti collaterali in CanExecute? –
Vedere i miei commenti – Marius