XAML WPF 的绑定/引用方法

Posted

技术标签:

【中文标题】XAML WPF 的绑定/引用方法【英文标题】:Binding/Referencing Method to XAML WPF 【发布时间】:2014-03-09 15:13:48 【问题描述】:

我有这个 xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:l="clr-namespace:My.Windows"
                    >
    <ObjectDataProvider x:Key="TitledWindow_Test" MethodName="Test" ObjectInstance=x:Type l:TitledWindow">
    <ControlTemplate x:Key="TitledWindowControlTemplateKey" x:Name="PART_ControlTemplate" TargetType="x:Type l:TitledWindow"
        <Rectangle>
            <Rectangle.Style>
                <EventSetter Event="Mouse.MouseEnter" Handler="StaticResource TitledWindow_Test">
            </Rectangle.Style>
        </Rectangle>
    </ControlTemplate>
</ResourceDictionary>

还有我的 c# 代码:

namespace My.Windows

    public partial class TitledWindow : Window
    
        public void Test()
        
            MessageBox.Show("Test");
        
    

问题是我收到以下错误:

错误 1 'ResourceDictionary' 根元素需要 x:Class 属性来支持事件 XAML 文件中的处理程序。删除 MouseEnter 事件的事件处理程序, 或向根元素添加 x:Class 属性。

【问题讨论】:

你想做什么?? 我想通过 XAML 将多个处理程序添加到唯一事件 @Jovan - 你不能在资源字典后面的代码中使用方法吗?我认为您不能像这样将 ObjectDataProvider 挂钩到 RoutedEvent 以及委托具有不同签名的地方。 那么我怎样才能使用这种方法或任何方法..? 检查我的答案是否在 ResourceDictionary 中有代码。 【参考方案1】:

您可以通过将代码附加到您的 ResourceDictionary 来做到这一点。实现这一目标的几个简单步骤是:

说 ResourceDictionary 文件名为 CustomResources.xaml。在您的 ResourceDictionary 之外的同一目录中添加另一个文件,名称为 CustomResources.xaml.cs。创建继承自 ResourceDictionary 的 partial class CustomResources

为 MouseEnter 声明你的处理程序,后面的代码就准备好了。

using System;
using System.Windows;
namespace WpfApplication1

    public partial class CustomResources : ResourceDictionary
    
        public void MouseEnter(object sender, EventArgs e)
        
            MessageBox.Show("Test");
        
    

现在,在 XAML 中设置 x:Class 属性并将处理程序设置为 MouseEnter

XAML:

<ResourceDictionary
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="WpfApplication1.CustomResources"
             xmlns:local="clr-namespace:WpfApplication1">
    <ControlTemplate x:Key="TitledWindowControlTemplateKey" 
                     x:Name="PART_ControlTemplate"
                     TargetType="x:Type local:TitleWindow">
        <Rectangle>
            <Rectangle.Style>
                <Style TargetType="Rectangle">
                    <EventSetter Event="Mouse.MouseEnter" Handler="MouseEnter"/>
                </Style>
            </Rectangle.Style>
        </Rectangle>
    </ControlTemplate>    
</ResourceDictionary>

【讨论】:

等一下... xD 这很好,但是如果我在我的 TitledWindow 类中定义了这些方法,因为那是使用这个 ResourceDictionary 的类呢? 为此,您必须在该类上创建ICommand 并在此处使用交互触发器绑定到命令。但是,从 ResourceDictionary 直接绑定到该方法是不可能的。或者您可以将这个资源完全移动到Window.Resources 部分下,您绝对可以直接从后面的代码中挂钩处理程序。 啊,好吧,我想我将不得不使用交互触发器,我读过它们,但我希望有更优雅的东西,不过谢谢! 首先非常感谢这个问题和答案。我遇到了完全相同的问题,但我希望选中或未选中复选框的回调。我已经在您的答案中添加了 MessageBox,以查看是否调用了正确的回调。我目前的问题是,我的回调函数 CheckBox_Checked 甚至在之前被调用并且窗口被显示并且我得到了一个异常。 PresentationFramework.dll 中发生了“System.InvalidOperationException”类型的未处理异常恐怕应用程序尚未完全初始化。任何想法,我如何检查初始化是否完成?【参考方案2】:

问题是Template 需要知道它所应用的对象是否有MouseEnter。不幸的是,即使将您的x:Type 应用到模板,xaml 编译器也没有足够的能力继续运行。

我之前做过类似的事情,让ResourceDictionary 识别我正在模板的孔隙,看起来我使用了一种风格来绕过它。 http://winchrome.codeplex.com/SourceControl/latest#WinChrome/UI/VS2012ResourceDictionary.xaml 中的完整代码。

<ResourceDictionary ... >

<Style x:Key="CloseButtonStyle" TargetType="x:Type Button" >
  ...
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="x:Type Button">
                <Border x:Name="bd" ....>
                ....
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True" SourceName="bd">
                        <Setter Property="Background" TargetName="bd" Value="DynamicResource x:Static SystemColors.ControlLightLightBrushKey"/>
                        ... 
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" TargetName="bd">
                          ...
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

但是,您想通过StaticResource ... 将您的处理程序绑定到您的objectDataPresenter 上的方法,我不确定您是否可以。相反,您最好使用普通绑定Binding Path=... 绑定到DataContext,我认为您仍然可以通过StaticResource.. 提供DataContext

【讨论】:

但是为什么Template 需要知道她属于哪个类,当我试图做的只是绑定到对象并通过StaticResource Key 提取它的方法时......顺便说一句,如果你想检查我的:link我回答了你的问题【参考方案3】:

您需要添加 x:class 属性并指定资源的位置以及事件处理程序的位置。 有关此示例,请参阅 Is it possible to set code behind a resource dictionary in WPF for event handling?。

【讨论】:

以上是关于XAML WPF 的绑定/引用方法的主要内容,如果未能解决你的问题,请参考以下文章

WPF C#代码中引用XAML中的控件

WPF中的xaml引用不同项目间资源的问题

wpf中,如何引用其他xaml文件中的Resources

WPF---MVVM初尝试

wpf开发中 xaml 添加名称空间

c#WPF XAML对ComboBox.Resources项的RelativeSource引用