【问题标题】:Binding/Referencing Method to XAML WPFXAML 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 中有代码。

标签: c# wpf xaml events binding


【解决方案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?

【讨论】:

    猜你喜欢
    • 2011-12-16
    • 2011-07-15
    • 2016-07-31
    • 2017-08-20
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    • 2015-11-23
    • 2011-02-23
    相关资源
    最近更新 更多