以下是两个 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/