2010-11-04 15 views
6

Tôi thực sự gãi đầu với cái này. Tôi có một cửa sổ chính mở ra một hộp thoại. Sau khi hộp thoại đóng, phương thức CanExecute trên các lệnh bị ràng buộc trong hộp thoại vẫn đang thực hiện. Điều này đang gây ra một số vấn đề nghiêm trọng trong đơn đăng ký của tôi.Khi nào ui tách khỏi lệnh?

Ví dụ:

MainWindow có nút có trình xử lý nhấp chuột. Đây là xử lý sự kiện click:

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     DialogWindow window = new DialogWindow(); 
     window.ShowDialog(); 
    } 

Trong hộp thoại tôi ràng buộc một mục kiểm soát tới một tài nguyên tĩnh trong cửa sổ hộp thoại, và mỗi mục trong danh sách có một lệnh:

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

Đây là 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; } 

Và đây là việc thực hiện 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; 
    } 
} 

Bây giờ, nếu tôi đóng cửa sổ hộp thoại và đặt điểm ngắt trong phương thức CanExecute (Tôi đang sử dụng Prism DelegateCommand với đăng ký sự kiện yếu) trên viewmodel, tôi nhận thấy rằng nó kích hoạt mặc dù hộp thoại đã bị đóng. Tại sao trên trái đất là sự ràng buộc giữa các nút trong hộp thoại và lệnh trên ViewModel vẫn còn sống?

Và tôi đang kiểm tra xem nó đang được thực hiện bằng cách đóng cửa sổ và sau đó thiết lập một điểm ngắt trong phương thức "CanClickMe" trong chế độ xem. Nó sẽ được thực hiện trong một thời gian, sau đó đột nhiên dừng lại (có thể do GC). Hành vi không xác định này đang gây ra vấn đề bởi vì trong ứng dụng thực tế, viewmodel có thể đã được xử lý.

+0

Tại thời điểm nào bạn thấy điều này? Ví dụ cửa sổ sẽ vẫn nằm trong phạm vi sau khi nó đóng, cho đến khi bạn rời khỏi sự kiện Click. Điều này cho phép người gọi truy cập các thuộc tính trong cửa sổ (ví dụ, trong cửa sổ Tùy chọn). Ngoài ra, những gì trong CanExecute đang gây ra một vấn đề? Có thể vấn đề thực sự là bạn đang tạo ra các hiệu ứng phụ trong CanExecute? –

+0

Xem nhận xét của tôi – Marius

Trả lời

0

Tôi đã nhìn thấy điều này nhiều lần trong các dự án khác nhau, tôi không chắc liệu con bọ đáng sợ này có ẩn chứa trong ứng dụng của bạn hay không, nhưng đáng để kiểm tra.

Có một known memory leak issue trong WPF 3.5 (bao gồm SP1), về cơ bản bạn có thể gặp phải nếu bạn đang ràng buộc với thứ không phải là DependencyProperty hoặc không triển khai INotifyPropertyChanged. Và đây chính xác là mã của bạn.

Chỉ cần triển khai INotifyPropertyChanged trên ItemViewModel và xem cách thức hoạt động. Hi vọng điêu nay co ich.

+1

Tôi đã triển khai INotifyPropertyChanged trên ItemViewModel, nhưng điều này không giúp ích gì. – Marius

0

Bạn có thể xóa Bộ sưu tập CommandBindings trong cửa sổ của mình khi đóng cửa sổ.

0

thay vì phải lệnh của bạn như một thuộc tính, bạn có thể thử như sau:

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

Bạn có thể sử dụng các mẫu WeakEvent để giảm thiểu vấn đề này. Vui lòng tham khảo câu hỏi Stackoverflow sau: Is Josh Smith's implementation of the RelayCommand flawed?

+0

Không có gì sai sót về việc triển khai, CommandManager ngụ ý mẫu sự kiện yếu một cách chính xác (cũng là câu trả lời được chấp nhận trong câu hỏi bạn đang đề cập đến các trạng thái) – Marius

Các vấn đề liên quan