2010-11-04 111 views
6

我真的用这个挠我的脑袋。我有一个打开对话框的主窗口。对话框关闭后,对话框中绑定命令的CanExecute方法仍在执行。这在我的应用程序中造成了一些严重的问题。ui何时从命令中分离?

示例:

MainWindow具有带点击处理程序的按钮。这是Click事件处理程序:

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; 
    } 
} 

现在,如果关闭对话框窗口并在ViewModel的CanExecute(我使用Prism DelegateCommand与弱事件订阅)方法中设置断点,我注意到它会触发,尽管对话框已关闭。为什么对话框中的按钮与ViewModel上的命令之间的绑定仍然存在?

我正在通过关闭窗口并在稍后在viewmodel的“CanClickMe”方法中设置一个断点来检查它是否正在执行。它会被执行一段时间,然后突然停止(可能是由于GC)。这种非恶意行为正在引发问题,因为在实际应用中,视角模型可能已经被处置。

+0

在什么时候你看到这个?窗口实例在关闭后仍处于范围内,直到您离开Click事件。这是为了允许调用者访问窗口中的属性(例如,考虑一个选项窗口)。另外,CanExecute中的内容会导致问题?问题实际上是你在CanExecute中创建副作用吗? – 2010-11-04 12:46:28

+0

查看我的评论 – Marius 2010-11-04 13:09:20

回答

0

我在不同的项目中多次看到过这个问题,我不确定这个令人毛骨悚然的bug是否也潜伏在你的应用中,但值得检查。

在WPF 3.5(包括SP1)中有一个known memory leak issue,基本上如果你绑定的东西不是DependencyProperty或者没有实现INotifyPropertyChanged,你可以遇到它。这正是你的代码所关心的。

只是执行INotifyPropertyChangedItemViewModel,看看它是如何发展。希望这可以帮助。

+1

我在ItemViewModel上实现了INotifyPropertyChanged,但这没有帮助。 – Marius 2011-03-04 08:32:37

0

关闭时,可以清除窗口的CommandBindings集合。

0

,而不是作为一个属性你的命令,你可以尝试以下方法:

public ICommand CommandClickMe 
{ 
    get 
    { 
     return new RelayWpfCommand<object>((obj)=>System.Console.Out.WriteLine("Hei mom"), obj => CanClickMe()); 
    } 
} 
相关问题