WPF:如何通过XAML将整个控件作为CommandParameter传递?

9

我正在使用MVVM模式,自定义的命令对象由ViewModel层提供。一个ViewModel对象可以通过DataContext属性连接到许多视图对象(如窗口、页面等)。在ICommand.CanExecute()中,我想检查与ViewModel命令相关的一些控件中是否存在验证错误。一个ViewModel可以提供多个命令,每个命令都有自己的一组控件用于验证验证错误。因此,伪XAML代码如下:

<Button.CommandParameter>
    <x:Array Type="sys_win:DependencyObject">
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
    </x:Array>
</Button.CommandParameter>

第二个问题是特定的命令可能会被控制调用,而该控件本身是集合项的DataTemplate的一部分(在我的情况下,是ListBoxItem数据模板的一部分)。我的模板化列表框项有两个文本框(绑定到对应ViewModel的两个属性)和一个按钮,该按钮调用ViewModel命令。因此,在命令CanExecute()中,我需要检查某些窗口控件和属于此列表项的两个文本框的验证错误,而不是其他项。如果我想将ListBoxItem.IsSelected属性作为CommandParameter传递,则下面的代码可以正常工作:
<Button DataContext="{Binding}" 
        Command="{Binding Path=SwitchCommand}"
        CommandParameter="{Binding Path=IsSelected, RelativeSource={
                                   RelativeSource
                                   Mode=FindAncestor,
                                   AncestorType={x:Type ListBoxItem}}}"/>

但是我该如何将整个(DependencyObject)ListBoxItem作为CommandParameter传递?并且通过{Binding RelativeSource}传递的这个ListBoxItem如何与第一个代码示例中的其他当前窗口控件混合使用?


非常抱歉,但我该如何在xaml中添加对控件的引用?

<Button.CommandParameter>
    <x:Array Type="sys_win:DependencyObject">
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
    </x:Array>
</Button.CommandParameter>

StackOverflow不是一个论坛;如果您需要添加更多细节,请编辑您的问题。答案应该是答案,而不是关于问题的额外信息。 - user1228
2个回答

33

只需使用没有Path的绑定:

<Button DataContext="{Binding}" 
        Command="{Binding Path=SwitchCommand}"
        CommandParameter="{Binding RelativeSource=
                                   {RelativeSource
                                    Mode=FindAncestor,
                                    AncestorType={x:Type ListBoxItem}}}"/>

1

我不确定我是否正确阅读了您的示例,但似乎违反了MVVM原则的一部分。(如果我阅读不正确,请谅解)。

MVVM的想法是将ViewModel与任何XAML/View实体的依赖关系解耦。通过使CommandParameter取决于usercontrol,您正在打破这一点。我会在ViewModel中创建状态属性,并将usercontrol验证绑定到这些状态,然后在CanExecute中,您可以测试这些属性的值,而不是尝试绑定到usercontrol。


Doobi,英语不是我的母语,我对它的了解比正常水平要差,所以你对第一篇帖子的部分错误理解是我的错。ViewModel提供命令,这些命令利用ViewModel提供的属性。属性绑定到View控件,并通过IDataErrorInfo提供错误验证,其实现也是ViewModel的一部分。尽管在View中所有错误值都标记有特殊模板,但用户仍可能尝试调用其中一个使用(当前)错误值属性的ViewModel命令。为了阻止这种能力,我们必须在ICo中进行设置。 - P A V L I K
因为Command接收DependencyObjects列表,ViewModel保持独立于View。但是今天,经过深思熟虑,我得出结论,我的方法就像发明方轮一样,我拒绝了这个想法。 - P A V L I K
ICommand.Execute() 检查所有属性,这些属性的值由此命令使用。因此,我们在两个时机检查 ViewModel 属性是否存在错误:1)在 string IDataErrorInfo.this[string propertyName] 中当属性值更改时;2)在 ICommand.CanExecute 中当 WPF 引擎更新 UI 时。为了避免实现(2),我想通过将绑定到当前 ViewModel 命令的重要 ViewModel 属性的 View 控件列表作为 CommandParameter 传递,并通过 Validation.GetHasError(DependencyObject) 检查错误来进行检查。 - P A V L I K
@thomas-levesque -太好了,如果我想将当前控件作为参数传递怎么办?实际上,我想在按键快捷方式上将日历字段的值设置为当前日期。我已经添加了命令绑定和输入绑定。但是如何查看当前字段是否为日历字段呢?这可以从XAML本身发生吗?还是我需要将命令发送到.cs文件中? - coder9090

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接