2008-11-02 7 views
5

Je vais avoir du mal à comprendre comment fonctionne la liaison paramètre de commande.WPF CommandParameter Reliure Problème

Lorsque je crée une instance de la classe widget avant l'appel à InitializeComponent il semble fonctionner très bien. Les modifications apportées au paramètre (Widget) dans la fonction ExecuteCommand seront "appliquées" à _widget. C'est le comportement que je m'attendais.

Si l'instance de _widget est créé après InitializeComponent, je reçois des exceptions référence null pour e.Parameter dans la fonction ExecuteCommand.

Pourquoi est-ce? Comment est-ce que je fais fonctionner ceci avec le modèle MVP, où l'objet lié peut être créé après que la vue soit créée?

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

Répondre

4

InitializeCompenent traite le xaml associé au fichier. C'est à ce moment que la liaison CommandParameter est d'abord traitée. Si vous initialisez votre champ avant InitializeCompenent, votre propriété ne sera pas nulle. Si vous le créez après, c'est null.

Si vous voulez créer le widget après InitializeCompenent alors vous aurez besoin d'utiliser une propriété de dépendance. Le proeprty de dépendance soulèvera une notification qui fera l'CommandParameter à jour et donc il ne sera pas nul.

Voici un échantillon de la façon de faire TestWidget une propriété de dépendance.

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

Même avec la propriété de dépendance, vous avez encore besoin d'appeler CommandManager.InvalidateRequerySuggested pour forcer le CanExecute du commandement en cours d'évaluation.