【问题标题】:Is it possible to set code behind a resource dictionary in WPF for event handling?是否可以在 WPF 中的资源字典后面设置代码以进行事件处理?
【发布时间】:2018-04-25 23:24:15
【问题描述】:

是否可以在 WPF 中的资源字典后面设置代码。例如,在按钮的用户控件中,您在 XAML 中声明它。按钮单击的事件处理代码在控件后面的代码文件中完成。如果我要创建一个带有按钮的数据模板,我该如何为资源字典中的按钮单击编写事件处理程序代码。

【问题讨论】:

  • 执行此操作的正确方法是使用命令,它还使您能够启用和禁用按钮,而您可以按照某些答案建议的方式进行操作破解。

标签: wpf


【解决方案1】:

我想你要问的是你想要一个 ResourceDictionary 的代码隐藏文件。你完全可以做到这一点!实际上,您的操作方式与 Window 相同:

假设您有一个名为 MyResourceDictionary 的 ResourceDictionary。在 MyResourceDictionary.xaml 文件中,将 x:Class 属性放在根元素中,如下所示:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    x:Class="MyCompany.MyProject.MyResourceDictionary"
                    x:ClassModifier="public">

然后,使用以下声明创建一个名为 MyResourceDictionary.xaml.cs 的代码隐藏文件:

namespace MyCompany.MyProject
{
    partial class MyResourceDictionary : ResourceDictionary
    { 
       public MyResourceDictionary()
       {
          InitializeComponent();
       }     
       ... // event handlers ahead..
    }
}

你就完成了。你可以在后面的代码中添加任何你想要的东西:方法、属性和事件处理程序。

== Windows 10 应用更新 ==

如果您正在使用 UWP,还有一件事需要注意:

<Application x:Class="SampleProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:rd="using:MyCompany.MyProject">
<!-- no need in x:ClassModifier="public" in the header above -->

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!-- This will NOT work -->
                <!-- <ResourceDictionary Source="/MyResourceDictionary.xaml" />-->

                <!-- Create instance of your custom dictionary instead of the above source reference -->
                <rd:MyResourceDictionary />

            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

</Application>

【讨论】:

  • 作为ageektrapped 答案的附录:确保将代码隐藏类的完全限定名称放在 x:Class 属性中。 x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary" 否则,如果您只输入 x:Class="MyResourceDictionary",xaml 解析器将找不到您的类。
  • 确保在分部类代码隐藏中提供默认构造函数,并确保它调用 InitializeComponent()。 (在我的例子中,我使用 MEF 来导出资源字典。)
  • 更新了代码 sn-p 以获得赞成的评论。我觉得有必要完成答案;一个常见的错误。我刚刚做到了 :) 如果您不喜欢它,请还原。感谢您的回答。
  • 请注意(至少在 wp8.1 中)这不再有效,您必须创建一个您的资源字典引用的自定义用户控件
  • 您还必须将 ResourceDictionary 的 XAML 文件上的 Build Action 设置为“Page”,否则 InitializeComponent() 调用将无法编译。 (ResourceDictionary XAML 文件通常默认设置为“资源”。)
【解决方案2】:

我不同意“ageektrapped”...使用部分类的方法不是一个好习惯。那么,将 Dictionary 与页面分离的目的是什么?

从代码隐藏中,您可以使用以下方法访问 x:Name 元素:

Button myButton = this.GetTemplateChild("ButtonName") as Button;
if(myButton != null){
   ...
}

如果您想在加载自定义控件时连接到控件,可以在 OnApplyTemplate 方法中执行 this。需要重写 OnApplyTemplate 才能执行此操作。这是一种常见的做法,可让您的样式与控件保持断开连接。 (样式不应该依赖于控件,而控件应该依赖于有样式)。

【讨论】:

  • Phobis 我认为将 Dictionary 与页面分离的目的是关于主页 xaml 的可重用性和可读性。上述解决方案也对我有用。
【解决方案3】:

Gishu - 虽然这似乎是一种“通常不被鼓励的做法”,但您可能想要这样做的一个原因是:

文本框获得焦点时的标准行为是将插入符号放置在与控件失去焦点时相同的位置。如果您希望在整个应用程序中,当用户选择任何文本框时突出显示文本框的全部内容,那么在资源字典中添加一个简单的处理程序就可以了。

您希望默认用户交互行为与开箱即用行为不同的任何其他原因似乎都是资源字典中隐藏代码的良好候选者。

完全同意任何特定于应用程序功能的东西都不应该在资源字典后面的代码中。

【讨论】:

    【解决方案4】:

    添加....这些天,随着 {x:Bind ...} 的出现,如果您想将 DataTemplate 放入共享的 ResourceDictionary 文件中,则需要为该文件提供代码。

    【讨论】:

      【解决方案5】:

      XAML 用于构建不包含代码的对象图。
      数据模板用于指示如何在屏幕上呈现自定义用户对象......(例如,如果它是列表框项)行为不是数据模板专业领域的一部分。重绘解决方案...

      【讨论】:

      • 结论:你会推荐使用带有代码的资源 dic 吗?我从来没用过,我很怀疑。
      • 我不会——对我来说感觉不对。字典应该返回特定键的值。在 OP 的情况下,将代码与数据模板捆绑在一起。我宁愿尝试不同的方法。例如,使用 Command 模型。我需要更多关于 OP 问题的详细信息来推荐 diff 解决方案。
      • 完全不同意。在 MVVM 中,有一种情况下代码非常有用:开发附加属性。让它与后面的代码一起工作,然后将其移植到附加属性。这比简单地从头开始开发附加属性要快得多,除非你的大脑有曼哈顿那么大。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 2012-07-05
      • 1970-01-01
      • 1970-01-01
      • 2018-07-03
      相关资源
      最近更新 更多