无法在Datatemplate中设置CommandBinding

时间:2012-11-19 19:07:33

标签: c# .net wpf routed-commands

以下是两个xaml片段,唯一的区别是一个示例直接填充窗口的可视树和DataContext,而另一个示例通过应用数据模板构建相同的窗口。

Visual Tree Content / DataContext

<Window>
    <Window.DataContext>
        <local:MyType />
    </Window.DataContext>

    <DockPanel>
        <DockPanel.CommandBindings>
            <CommandBinding Command="ApplicationCommands.New"
                            CanExecute="OnCanExecuteNew"
                            Executed="OnExecuteNew"
                            />
        </DockPanel.CommandBindings>
        <ToolBarTray DockPanel.Dock="Top">
            <ToolBar>
                <Button Command="ApplicationCommands.New"
                        Content="New"
                        />
            </ToolBar>
        </ToolBarTray>
        <ContentPresenter Content="{Binding SomeProperty}" />
    </DockPanel>
</Window>

业务对象内容&amp;的DataTemplate

<Window>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:MyType}">
            <DockPanel>
                <DockPanel.CommandBindings>
                    <CommandBinding Command="ApplicationCommands.New"
                                    CanExecute="OnCanExecuteNew"
                                    Executed="OnExecuteNew"
                                    />
                </DockPanel.CommandBindings>
                <ToolBarTray DockPanel.Dock="Top">
                    <ToolBar>
                        <Button Command="ApplicationCommands.New"
                                Content="New"
                                />
                    </ToolBar>
                </ToolBarTray>
                <ContentPresenter Content="{Binding SomeProperty}" />
            </DockPanel>
        </DataTemplate>
    </Window.Resources>
    <Window.Content>
        <local:MyType />
    </Window.Content>
</Window>

第一个示例(可视化树内容和数据上下文)的工作原理可能是设计者在第二个示例中引发编译时错误时所预期的:“无法绑定到目标方法,因为它的签名或安全透明度与委托类型不兼容。“尽管存在设计器错误,我仍然可以在本地运行应用程序,我已经验证了正在执行的路由命令处理程序。当尝试在其他PC上运行应用程序时,应用程序在启动时静默失败,在Windows事件日志中留下xaml加载错误日志条目。当我从第二个代码段中删除命令绑定时,设计器错误消失了,应用程序在本地和其他PC上执行都没有问题。

请有人向我解释异常的原因以及如何在模板中指定命令绑定。

1 个答案:

答案 0 :(得分:2)

我可以在设计器中使用以下错误重现它(VS2010 SP1目标框架.NET4.0) System.Windows.Markup.XamlParseException: Failed to create a 'CanExecute' from the text 'OnCanExecuteNew'
System.ArgumentException: Error binding to target method.

但我可以构建应用程序,它可以在我的本地机器上运行 我认为设计师在这里的工作方式与WPF运行时不同。 在设计时应用模板并解析CommandBinding的事件处理程序时,模板的结果可视树仍然不是窗口可视树的一部分。这就是处理程序无法解决的原因。 作为一种解决方法,我会考虑以下选项 1)将CommandBindings放在窗口

<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.New"
                    CanExecute="OnCanExecuteNew"
                    Executed="OnExecuteNew"/>
</Window.CommandBindings>

2)在UserControl中包装数据模板的内容,并将事件处理程序放在其代码隐藏中。

UserControl.xaml

<UserControl x:Class="WpfApplication1.UserControl1">
    <DockPanel>
        <DockPanel.CommandBindings>
            <CommandBinding Command="ApplicationCommands.New"
                            CanExecute="OnCanExecuteNew"
                            Executed="OnExecuteNew"/>
        </DockPanel.CommandBindings>
        <ToolBarTray DockPanel.Dock="Top">
            <ToolBar>
                <Button Command="ApplicationCommands.New" Content="New"/>
            </ToolBar>
        </ToolBarTray>
        <ContentPresenter Content="{Binding SomeProperty}" />
    </DockPanel>
</UserControl>

Window.xaml

<DataTemplate DataType="{x:Type local:MyType}">
    <local:UserControl1/>
</DataTemplate>

3)根本不要使用CommandBindings并将命令对象放在视图模型(MVVM)中。

<Button Command="{Binding NewCommand}" Content="New"/>

作为一般规则,我建议避免紧密耦合数据模板和代码。数据模板应该是你所采取的东西并放在资源字典中。