2010-04-27 6 views
0

Je suis en train de détecter quand un élément est vérifié et qui article est cochée dans une zone de liste à l'aide Silverlight 4 et le cadre Prism. Je found this example sur la création de comportements, et essayé de le suivre, mais rien ne se passe dans le débogueur. J'ai trois questions:CheckBox pour Silverlight Behaviors commande MVVM Motif

  1. Pourquoi ma commande ne s'exécute-t-elle pas?
  2. Comment déterminer quel élément a été vérifié (c'est-à-dire passer un paramètre de commande)?
  3. Comment est-ce que je débogue ceci? (Là où je peux mettre des points de rupture pour commencer d'entrer dans cette)

Voici mon code:

Vue:

 <ListBox x:Name="MyListBox" ItemsSource="{Binding PanelItems, Mode=TwoWay}"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <CheckBox IsChecked="{Binding Enabled}" my:Checked.Command="{Binding Check}" /> 
         <TextBlock x:Name="DisplayName" Text="{Binding DisplayName}"/> 
        </StackPanel> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 

ViewModel:

public MainPageViewModel() 
{ 
    _panelItems.Add(new PanelItem 
    { 
     Enabled = true, 
     DisplayName = "Test1" 
    }); 

    Check = new DelegateCommand<object>(itemChecked); 
} 

public void itemChecked(object o) 
{ 
//do some stuff 
} 

public DelegateCommand<object> Check { get; set; } 

Comportement Classe

public class CheckedBehavior : CommandBehaviorBase<CheckBox> 
    { 
     public CheckedBehavior(CheckBox element) 
      : base(element) 
     { 
      element.Checked +=new RoutedEventHandler(element_Checked); 
     } 

     void element_Checked(object sender, RoutedEventArgs e) 
     { 
      base.ExecuteCommand(); 
     }    
    } 

classe Command

public static class Checked 
{ 
    public static ICommand GetCommand(DependencyObject obj) 
    { 
     return (ICommand) obj.GetValue(CommandProperty); 
    } 

    public static void SetCommand(DependencyObject obj, ICommand value) 
    { 
     obj.SetValue(CommandProperty, value); 
    } 

    public static readonly DependencyProperty CommandProperty = 
      DependencyProperty.RegisterAttached("Command", typeof(CheckBox), typeof(Checked), new 
      PropertyMetadata(OnSetCommandCallback)); 

    public static readonly DependencyProperty CheckedCommandBehaviorProperty = 
       DependencyProperty.RegisterAttached("CheckedCommandBehavior", typeof(CheckedBehavior), typeof(Checked), null); 

    private static void OnSetCommandCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     CheckBox element = dependencyObject as CheckBox; 
     if(element != null) 
     { 
      CheckedBehavior behavior = GetOrCreateBehavior(element); 
      behavior.Command = e.NewValue as ICommand; 
     } 
    } 
    private static CheckedBehavior GetOrCreateBehavior(CheckBox element) 
    { 
     CheckedBehavior behavior = element.GetValue(CheckedCommandBehaviorProperty) as CheckedBehavior; 
     if(behavior == null) 
     { 
      behavior = new CheckedBehavior(element); 
      element.SetValue(CheckedCommandBehaviorProperty, behavior); 
     } 

     return behavior; 
    } 
    public static CheckedBehavior GetCheckCommandBehavior(DependencyObject obj) 
    { 
     return (CheckedBehavior) obj.GetValue(CheckedCommandBehaviorProperty); 
    } 
    public static void SetCheckCommandBehavior(DependencyObject obj, CheckedBehavior value) 
    { 
     obj.SetValue(CheckedCommandBehaviorProperty, value); 
    }    

}

Répondre

2

Votre échantillon ne suffit pas pour une repro sur mon PC, mais voici ce que je voudrais corriger d'abord:

  • Les liaisons dans le DataTemplate sont manquantes ", Mode = TwoWay" si yo Vous voulez que la propriété Enabled soit définie dans votre PanelItem (- La liaison ItemsSource n'a pas besoin du Mode = TwoWay, mais c'est un détail mineur)
  • Le DataContext du ItemTemplate est l'instance de PanelItem, donc la liaison du La commande Check semble incorrecte: il n'y a pas de propriété Check sur PanelItem. La liaison doit être: mon: Checked.Command = "{Binding ElementName = MyListBox, Path = DataContext.Check}

Ce genre de choses est toujours difficile de débogage Regardez la fenêtre de sortie de VS, la liaison. Les erreurs (chemin non trouvé) y sont affichées Lorsque vous avez un callback de changement de DP (comme OnSetCommandCallback), un point d'arrêt vous indiquera comment la liaison est passée

Editer: ajouté après le 1er commentaire (car je ne peux pas utiliser la fonction de commentaire sur le PC que je dois utiliser maintenant) La propriété Command attach est définie comme type CheckBox dans la classe Checked, mais la propriété Check dans la VM est une DelegateCommand Je suis d'accord avec WPF sur la différence de type :-) La déclaration de propriété est comme ceci:

public static readonly DependencyProperty CommandProperty = 
    DependencyProperty.RegisterAttached( 
     "Command", typeof(CheckBox), 
     typeof(Checked), new PropertyMetadata(OnSetCommandCallback)); 

Le second paramètre doit être le type de propriété, donc je suppose que quelque chose comme ICommand dans votre cas.Par curiosité: dans OnSetCommandCallback, vous ne vous souciez pas de la valeur de la propriété Command (qui est dans e.NewValue). Comment reliez-vous une instance de CheckedBehavior à la propriété Check de la machine virtuelle?

Modifier après le deuxième commentaire: Non, le 2ème paragraphe ci-dessus n'est pas lié à votre question. Peut-être que cela n'a pas de sens. Je ne peux pas comprendre le rôle de CheckedBehavior.

En ce qui concerne la question de savoir quel élément est coché/décoché: de quoi avez-vous besoin plus précisément? Vous avez une instance de PanelItem, dont la propriété Enabled est définie sur true ou false via la fusion; donc les éléments cochés sont ceux avec Enabled = true.

Modifier après le 3e commentaire: Merci pour l'explication de vos besoins. Vous n'êtes pas vraiment en utilisant le paramètre de chemin de la liaison à la propriété ci-joint, vous pouvez écrire:

my:Checked.Command="{Binding}" 

De cette façon, e.NewValue est le PanelItem lié dans le OnSetCommandCallback. Donc, il pourrait être donné à l'instance CheckedBehavior (dans son constructeur), qui pourrait le transmettre lors de l'appel de Execute of ICommand.

+0

@Timores - Qu'est-ce que vous avez dit au sujet de la DataContext pour PanelItem ne pas être la même comme le ListBox a du sens. J'ai fait le changement comme vous l'avez suggéré et maintenant j'obtiens cette erreur: "Impossible de convertir le type Microsoft.Practices.Composite.Presentation.Commands.DelegateCommand'1 [System.Object] pour taper System.Windows.Controls.CheckBox." Si vous avez besoin de plus de code pour aider à résoudre les problèmes, s'il vous plaît faites le moi savoir et je vais essayer de vous l'obtenir. –

+0

Ok, d'abord les bonnes nouvelles. Le premier commentaire que vous avez fait sur le 2ème paramètre corrigé le problème de type de conversion que j'avais. Maintenant, je suis en mesure de voir l'élément soit coché/décoché dans ma machine virtuelle! Je ne suis pas certain de comprendre votre deuxième commentaire. Est-ce la raison pour laquelle je ne peux pas déterminer quel élément a été coché/décoché? Comment puis-je déterminer quel élément de la liste a réellement été traité? J'espère que cela a du sens et j'apprécie vraiment votre aide jusqu'à présent! –

+0

@Timores - Concernant l'édition deux: Si je pouvais obtenir la propriété DisplayName en tant que paramètre de commande qui serait idéal. Dans un exemple concret, j'aurais probablement une carte d'identité que je voudrais passer en arrière. –

0

CheckBehavior.cs:

public class CheckBehavior : CommandBehaviorBase<CheckBox> 
{ 
    public CheckBehavior(CheckBox element) : base(element) 
    { 
     element.Checked += OnElementChecked; 
     element.Unchecked += OnElementChecked; 
    } 

    private void OnElementChecked(object sender, RoutedEventArgs e) 
    { 
     if (sender is CheckBox && ((CheckBox)sender).IsPressed) 
     { 
      base.ExecuteCommand(); 
     } 
    } 
} 

CheckCommand.cs:

public class CheckCommand 
{ 
    public static ICommand GetCommand(DependencyObject obj) 
    { 
     return (ICommand)obj.GetValue(CommandProperty); 
    } 

    public static void SetCommand(DependencyObject obj, ICommand value) 
    { 
     obj.SetValue(CommandProperty, value); 
    } 

    public static object GetCommandParameter(DependencyObject obj) 
    { 
     return obj.GetValue(CommandParameterProperty); 
    } 

    public static void SetCommandParameter(DependencyObject obj, object value) 
    { 
     obj.SetValue(CommandParameterProperty, value); 
    } 

    public static readonly DependencyProperty CommandProperty = 
     DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(CheckCommand), new PropertyMetadata(OnSetCommandCallback)); 

    public static readonly DependencyProperty CommandParameterProperty = 
     DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(CheckCommand), new PropertyMetadata(OnSetCommandParameterCallback)); 

    public static readonly DependencyProperty CheckedCommandBehaviorProperty = 
     DependencyProperty.RegisterAttached("CheckedCommandBehavior", typeof(CheckBehavior), typeof(CheckCommand), null); 

    private static void OnSetCommandCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     CheckBox element = dependencyObject as CheckBox; 
     if (element != null) 
     { 
      CheckBehavior behavior = GetOrCreateBehavior(element); 
      behavior.Command = e.NewValue as ICommand; 
     } 
    } 

    private static void OnSetCommandParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     CheckBox element = dependencyObject as CheckBox; 
     if (element != null) 
     { 
      CheckBehavior behavior = GetOrCreateBehavior(element); 
      behavior.CommandParameter = e.NewValue; 
     } 
    } 

    private static CheckBehavior GetOrCreateBehavior(CheckBox element) 
    { 
     CheckBehavior behavior = element.GetValue(CheckedCommandBehaviorProperty) as CheckBehavior; 
     if (behavior == null) 
     { 
      behavior = new CheckBehavior(element); 
      element.SetValue(CheckedCommandBehaviorProperty, behavior); 
     } 

     return behavior; 
    } 
    public static CheckBehavior GetCheckCommandBehavior(DependencyObject obj) 
    { 
     return (CheckBehavior)obj.GetValue(CheckedCommandBehaviorProperty); 
    } 
    public static void SetCheckCommandBehavior(DependencyObject obj, CheckBehavior value) 
    { 
     obj.SetValue(CheckedCommandBehaviorProperty, value); 
    } 
} 

Et par exemple:

<CheckBox Commands:CheckCommand.Command="{Binding MyCheckCommand}}" 
      Commands:CheckCommand.CommandParameter="{Binding}"/>