2008-11-02 47 views
5

Tôi đang gặp một số sự cố khi hiểu cách hoạt động của tham số lệnh.WPF CommandParameter Binding Problem

Khi tôi tạo một thể hiện của lớp tiện ích trước khi cuộc gọi đến InitializeComponent nó có vẻ hoạt động tốt. Các sửa đổi đối với tham số (Widget) trong hàm ExecuteCommand sẽ được "áp dụng" cho _widget. Đây là hành vi tôi mong đợi.

Nếu cá thể của _widget được tạo sau khi InitializeComponent, tôi nhận được ngoại lệ tham chiếu null cho e.Parameter trong hàm ExecuteCommand.

Tại sao điều này? Làm thế nào để làm cho công việc này với mô hình MVP, nơi mà các đối tượng bị ràng buộc có thể được tạo ra sau khi xem được tạo ra?

public partial class WidgetView : Window 
{ 
    RoutedCommand _doSomethingCommand = new RoutedCommand(); 

    Widget _widget; 

    public WidgetView() 
    { 
     _widget = new Widget(); 
     InitializeComponent(); 
     this.CommandBindings.Add(new CommandBinding(DoSomethingCommand, ExecuteCommand, CanExecuteCommand)); 
    } 

    public Widget TestWidget 
    { 
     get { return _widget; } 
     set { _widget = value; } 
    } 

    public RoutedCommand DoSomethingCommand 
    { 
     get { return _doSomethingCommand; } 
    } 

    private static void CanExecuteCommand(object sender, CanExecuteRoutedEventArgs e) 
    { 
     if (e.Parameter == null) 
      e.CanExecute = true; 
     else 
     { 
      e.CanExecute = ((Widget)e.Parameter).Count < 2; 
     } 
    } 

    private static void ExecuteCommand(object sender, ExecutedRoutedEventArgs e) 
    { 
     ((Widget)e.Parameter).DoSomething(); 
    } 
} 



<Window x:Class="CommandParameterTest.WidgetView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="WidgetView" Height="300" Width="300" 
    DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <StackPanel> 
     <Button Name="_Button" Command="{Binding DoSomethingCommand}" 
      CommandParameter="{Binding TestWidget}">Do Something</Button> 
    </StackPanel> 
</Window> 


public class Widget 
{ 
    public int Count = 0; 
    public void DoSomething() 
    { 
     Count++; 
    } 
} 

Trả lời

4

InitializeCompenent xử lý xaml được liên kết với tệp. Vào thời điểm này, ràng buộc CommandParameter được xử lý lần đầu tiên. Nếu bạn khởi tạo trường của bạn trước khi InitializeCompenent thì tài sản của bạn sẽ không rỗng. Nếu bạn tạo nó sau đó nó là null.

Nếu bạn muốn tạo tiện ích con sau khi InitializeCompenent thì bạn sẽ cần sử dụng thuộc tính phụ thuộc. Các proeprty phụ thuộc sẽ nâng cao một thông báo rằng sẽ gây ra các CommandParameter được cập nhật và do đó nó sẽ không được null.

Đây là ví dụ về cách làm cho TestWidget trở thành thuộc tính phụ thuộc.

public static readonly DependencyProperty TestWidgetProperty = 
    DependencyProperty.Register("TestWidget", typeof(Widget), typeof(Window1), new UIPropertyMetadata(null)); 
public Widget TestWidget 
{ 
    get { return (Widget) GetValue(TestWidgetProperty); } 
    set { SetValue(TestWidgetProperty, value); } 
} 
0

Ngay cả với thuộc tính phụ thuộc, bạn vẫn cần gọi CommandManager.InvalidateRequerySuggested để buộc CanExecute của lệnh được đánh giá.