Silverlight MVVM模式的CheckBox命令行为

时间:2010-04-27 20:40:28

标签: silverlight mvvm .net-4.0

我正在尝试检测 时检查项目,并使用Silverlight 4和Prism框架在ListBox中检查哪个项目。我found this example关于创建行为,并试图遵循它,但调试器中没有发生任何事情。我有三个问题:

  1. 为什么我的命令不执行?
  2. 如何确定检查了哪个项目(即传递命令参数)?
  3. 我该如何调试? (即我可以在哪里放置断点开始踩到这个)
  4. 这是我的代码:

    查看:

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

    视图模型:

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

    行为类

    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();
            }               
        }
    

    命令类

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

    }

2 个答案:

答案 0 :(得分:2)

您的样本不足以在我的电脑上进行复制,但以下是我首先要纠正的事情:

  • 如果要在PanelItem中设置Enabled属性,则DataTemplate中的绑定缺少“,Mode = TwoWay” ( - ItemsSource绑定不需要Mode = TwoWay,但这是一个小细节)
  • ItemTemplate的DataContext是PanelItem实例,因此Check命令的绑定似乎错误:PanelItem上没有Check属性。绑定应该是: my:Checked.Command =“{Binding ElementName = MyListBox,Path = DataContext.Check}

这种东西总是难以调试。看看VS的输出窗口;在那里显示绑定错误(找不到路径)。当你有一个DP更改回调(比如OnSetCommandCallback)时,会有一个断点告诉你绑定是如何进行的。

编辑:在第一条评论后添加(因为我无法使用PC上的评论功能,我现在必须使用) Command附加属性在Checked类中定义为类型CheckBox,但VM中的Check属性是DelegateCommand。我同意WPF关于类型不匹配的问题:-) 财产声明是这样的:

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

第二个参数应该是属性类型,所以我想你的情况就像ICommand一样。

出于好奇:在OnSetCommandCallback中,您不关心为Command属性设置的值(在e.NewValue中)。如何将CheckedBehavior的实例与VM的Check属性相关联?

第二次评论后编辑: 不,上面的第2段与您的问题无关。也许这没有意义。我无法弄清楚CheckedBehavior的作用。

关于选中/取消选中哪个项目的问题:您更准确地需要什么?您有一个PanelItem实例,其Enabled属性通过biding设置为true或false;所以选中的项目是Enabled = true。

第3次评论后编辑: 感谢您解释您的需求。你并没有真正使用绑定到附加属性的path参数,你可以写:

my:Checked.Command="{Binding}"

这样,e.NewValue就是OnSetCommandCallback中绑定的PanelItem。所以它可以被赋予CheckedBehavior实例(在它的构造函数中),它可以在调用ICommand的Execute时转发它。

答案 1 :(得分: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);
    } 
}

例如:

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