Я действительно почесываю голову этим. У меня есть mainwindow, который открывает диалог. После закрытия диалога метод CanExecute в командах, связанных в диалоговом окне, все еще выполняется. Это вызывает некоторые серьезные проблемы в моем приложении.Когда ui отсоединяется от команд?
Пример:
MainWindow имеет кнопку с обработчиком щелчка. Это обработчик события нажатия:
private void Button_Click(object sender, RoutedEventArgs e)
{
DialogWindow window = new DialogWindow();
window.ShowDialog();
}
В диалоговом окне я связать элементы управления для статического ресурса в диалоговом окне, и каждый элемент в списке имеет команду:
<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>
Это модели представления:
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; }
И это реализация 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;
}
}
Теперь, если я закрою диалоговое окно и задаю точку останова в методе CanExecute (я использую Prism DelegateCommand со слабой подпиской на события) на модели viewmodel, я заметил, что он вызывает, хотя диалог был закрыт. Почему на самом деле связь между кнопкой в диалоговом окне и командой на ViewModel все еще жива?
И я проверяю, выполняется ли его, закрывая окно и позднее устанавливая точку останова в методе CanClickMe в модели viewmodel. Он будет выполняться некоторое время, а затем внезапно остановится (вероятно, из-за GC). Это не-детерминированное поведение вызывает проблемы, поскольку в реальном приложении модель просмотра может быть уже удалена.
В какой момент вы это видите? Экземпляр окна будет по-прежнему находиться в области действия после его закрытия, пока вы не покинете событие Click. Это позволит вызывающему пользователю получить доступ к свойствам в окне (подумайте, например, о окне «Параметры»). Кроме того, что в CanExecute вызывает проблему? Может ли проблема на самом деле заключаться в том, что вы создаете побочные эффекты в CanExecute? –
Мои комментарии – Marius