2008-11-02 21 views
5

Mam trudności ze zrozumieniem sposobu działania wiązania parametrów polecenia.Problem związany z wiązaniem polecenia Command WPF

Kiedy tworzę instancję klasy widżetów przed wywołaniem InitializeComponent, wydaje mi się, że działa dobrze. Modyfikacje parametru (Widget) w funkcji ExecuteCommand zostaną "zastosowane" do _widget. Takie zachowanie się spodziewałem.

Jeśli instancja _widget zostanie utworzona po InitializeComponent, otrzymam wyjątki odwołania null dla e.Parameter w funkcji ExecuteCommand.

Dlaczego tak jest? Jak mogę to zrobić przy użyciu wzorca MVP, w którym obiekt powiązany może zostać utworzony po utworzeniu widoku?

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

Odpowiedz

4

InitializeCompenent przetwarza kod XAML powiązany z plikiem. W tym momencie powiązanie CommandParameter jest najpierw przetwarzane. Jeśli zainicjujesz swoje pole przed InitializeCompenent, twoja własność nie będzie miała wartości NULL. Jeśli utworzysz go później, będzie to zero.

Jeśli chcesz utworzyć widget po InitializeCompenent, musisz użyć właściwości zależności. Proentność zależności wywoła powiadomienie, które spowoduje aktualizację parametru CommandParameter, a zatem nie będzie miało wartości NULL.

Oto przykładowy sposób uczynienia TestWidget właściwość zależności.

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

Nawet przy właściwość zależność, trzeba jeszcze zadzwonić CommandManager.InvalidateRequerySuggested zmusić CanExecute polecenia są oceniane.

Powiązane problemy