c# - 无法在数据模板内设置 CommandBinding

标签 c# .net wpf routed-commands

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

可视化树内容/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>

业务对象内容和数据模板

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

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

请有人向我解释一下异常的原因以及如何在模板内指定命令绑定(bind)。

最佳答案

我可以在设计器中重现它并出现以下错误(VS2010 SP1目标框架.NET4.0) System.Windows.Markup.XamlParseException: Failed to create a 'CanExecute' from the text 'OnCanExecuteNew'<br/> 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 中,并将事件处理程序放入其代码隐藏中。

用户控件.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>

窗口.xaml

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

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

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

作为一般规则,我建议避免数据模板和代码隐藏的紧密耦合。数据模板应该是您获取并放入资源字典中的内容。

关于c# - 无法在数据模板内设置 CommandBinding,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13460421/

相关文章:

c# - app.UseHsts() 和 app.UseExceptionHandler() 有什么区别?

.net - 绑定(bind)到 DataTemplate 中的父 DataContext

c# - 如何编写单元测试以确定对象是否可以被垃圾回收?

c# - 在 wpf 应用程序中运行其他控制台进程之前如何等待控制台进程完成?

c# - 数据不会永久保存到 SQL 表中

c# - 可以集成到 C# 应用程序中的差异工具

c# - 如何在 ios 中以编程方式打开设置

c# - 如何让 VS 不复制我的 C# 文件

wpf - 在 WPF 中裁剪图像

c# - 对不一致的行结尾说"is"?