【问题标题】:Namespaced Dependency Properties in WPFWPF 中的命名空间依赖属性
【发布时间】:2013-11-24 19:27:12
【问题描述】:

如何创建依赖属性,如:

Stylus.IsFlicksEnabled
Stylus.IsPressAndHoldEnabled

我正在创建带有 TitleBar 的自定义窗口......我想要的只是在命名空间中分隔 TitleBar 宽度、高度、边距、背景等:

TitleBar.Width
TitleBar.Height
...

而不是创建 TitleBarWidthProperty,并像 TitleBarWidth="value" 一样访问它

没有误解 TitleBar 在我的窗口中不受控制,它不作为一个整体存在,它只是窗口的内容部分,我想要的只是创建命名空间分隔的 DP,TitleBar 组件将从中绑定,例如:

<Window Background="Blue"
        TitleBar.Background="Red"
>
</Window>

@Mike Strobel 我认为这证明你所说的事情是错误的......

【问题讨论】:

    标签: wpf namespaces


    【解决方案1】:

    具有这些类型限定名称的依赖属性称为附加依赖属性。它们的创建方式与常规依赖属性类似,但有以下区别:

    1. 应该通过调用 DependencyProperty.RegisterAttached() 来初始化 DependencyProperty 字段,而不是简单地调用 Register()

    2. 因为属性值被“附加”到可能不知道该属性的对象上,所以通常不会创建 CLR 属性包装器。相反,创建一对静态 Get/Set 方法:

      public static double GetWidth(DependencyObject target) { /* ... */ }
      public static void SetWidth(DependencyObject target, double value) { /* ... */ }
      

    有趣的是,XAML 解析器可以利用 不是 依赖属性的附加属性。只需要相关的静态 Get/Set 方法。

    虽然核心 WPF 中一些最常见的用例是声明要分配给子元素的属性,例如,由 Panel 排列的元素,但这并不是唯一的用例。这个想法是,由任意类型声明的属性可用于在任何对象上设置值,即使它不知道该属性。这使得它们对Attached Behaviors 等有用。

    在您的情况下,您似乎想要声明可以在样式或模板中引用的新布局相关属性。这也是一个常见的用例。示例:

    public static class TitleBar {
        public static readonly DependencyProperty WidthProperty =
            DependencyProperty.RegisterAttached(
                "Width",
                typeof(double),
                typeof(TitleBar),
                new FrameworkPropertyMetadata(double.NaN));
    
        public static double GetWidth(DependencyObject target) {
            return (double)target.GetValue(TitleBarProperty);
        }
    
        public static void SetWidth(DependencyObject target, double value) {
            target.SetValue(TitleBarProperty, value);
        }
    
        // TODO: Add similar members for additional properties...
    }
    

    如果您想鼓励仅在 Window 元素上设置属性,只需将 Get/Set 方法的第一个参数替换为 Window 而不是 DependencyObject

    应在何处声明属性取决于用例。如果属性仅对特定 UI 元素有意义(例如,GridRowColumn 声明为布局提示),则该元素应声明该属性。如果要在样式或模板中引用其他元数据,您可能应该在适当命名的静态类中声明它(如我上面的示例中所示)。如果要将其用作附加行为的一部分,则应在该行为的类中声明。

    声明属性的类的名称是出现在 XAML 引用中 . 左侧的名称。在上面的 TitleBar 示例中,Width 属性在 XAML 中将被引用为 ns:TitleBar.Width,其中 ns 映射到包含 TitleBar 类的 CLR 命名空间。

    【讨论】:

    • 据我了解附加属性的阅读以及我在实践中看到的那样,它将依赖属性附加到子元素上,我只想分隔依赖属性名称...如果我错了,请纠正我
    • 该属性将在 XAML 中属性设置器附加到的任何元素上设置。这个想法不一定是将值设置在 child 元素上,但它可以设置在不知道该属性的元素上,因为它是由另一种类型声明的(例如,Grid 定义可以在任何元素上设置的行和列属性)。
    • 我不确定您在编辑中指的是什么。 Grid.IsSharedSizeScope 可以设置在任何元素上。它旨在设置在 Grid 元素的 ancestor 上,但这当然不是一般附加属性的要求。
    • 嗯,如果我创建它,我应该把依赖属性放在哪里?无论如何,我将如何获得 TitleBar 前缀?
    【解决方案2】:

    那是attached dependency property。它们可以定义为任何类型on任何类型。

    这是我用来创建附加依赖属性的 sn-p。

    <?xml version="1.0" encoding="utf-8"?>
    <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
      <CodeSnippet Format="1.0.0">
        <Header>
          <SnippetTypes>
            <SnippetType>Expansion</SnippetType>
          </SnippetTypes>
          <Title>SnippetFile1</Title>
          <Author>Will Sullivan</Author>
          <Description>Attached Property</Description>
          <HelpUrl>
          </HelpUrl>
          <Shortcut>AP</Shortcut>
        </Header>
        <Snippet>
          <Declarations>
            <Literal Editable="true">
              <ID>AttachedPropertyName</ID>
              <ToolTip>The name of the property</ToolTip>
              <Default>PropertyName</Default>
              <Function>
              </Function>
            </Literal>
            <Literal Editable="true">
              <ID>PropertyType</ID>
              <ToolTip>The Property Type</ToolTip>
              <Default>object</Default>
              <Function>
              </Function>
            </Literal>
            <Literal Editable="true">
              <ID>ClassName</ID>
              <ToolTip>The name of the containing class</ToolTip>
              <Default>object</Default>
              <Function>ClassName()</Function>
            </Literal>
            <Literal Editable="true">
              <ID>TargetType</ID>
              <ToolTip>The type on which the DependencyProperty is attached</ToolTip>
              <Default>DependencyObject</Default>
              <Function>
              </Function>
            </Literal>
          </Declarations>
          <Code Language="csharp"><![CDATA[#region $AttachedPropertyName$ Attached DependencyProperty
            /// <summary>
            /// An Attached <see cref="DependencyProperty"/> of type <see cref="$PropertyType$"/> defined on <see cref="$TargetType$">$TargetType$ instances</see>.
            /// </summary>
            public static readonly DependencyProperty $AttachedPropertyName$Property = DependencyProperty.RegisterAttached(
              $AttachedPropertyName$PropertyName,
              typeof($PropertyType$),
              typeof($ClassName$),
              new FrameworkPropertyMetadata(default($PropertyType$), On$AttachedPropertyName$Changed)
            );
    
            /// <summary>
            /// The name of the <see cref="$AttachedPropertyName$Property"/> Attached <see cref="DependencyProperty"/>.
            /// </summary>
            public const string $AttachedPropertyName$PropertyName = "$AttachedPropertyName$";
    
            /// <summary>
            /// Sets the value of the <see cref="$AttachedPropertyName$Property"/> on the given <paramref name="element"/>.
            /// </summary>
            /// <param name="element">The <see cref="$TargetType$">target element</see>.</param>
            public static void Set$AttachedPropertyName$($TargetType$ element, $PropertyType$ value)
            {
                element.SetValue($AttachedPropertyName$Property, value);
            }
    
            /// <summary>
            /// Gets the value of the <see cref="$AttachedPropertyName$Property"/> as set on the given <paramref name="element"/>.
            /// </summary>
            /// <param name="element">The <see cref="$TargetType$">target element</see>.</param>
            /// <returns><see cref="$PropertyType$"/></returns>
            public static $PropertyType$ Get$AttachedPropertyName$($TargetType$ element)
            {
                return ($PropertyType$)element.GetValue($AttachedPropertyName$Property);
            }
    
            /// <summary>
            /// Called when <see cref="$AttachedPropertyName$Property"/> changes
            /// </summary>
            /// <param name="d">The <see cref="DependencyObject">event source</see>.</param>
            /// <param name="e"><see cref="DependencyPropertyChangedEventArgs">event arguments</see></param>
            private static void On$AttachedPropertyName$Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                $end$
            }
            #endregion]]></Code>
        </Snippet>
      </CodeSnippet>
    </CodeSnippets>
    

    【讨论】:

    • 据我了解附加属性的阅读以及我在实践中看到的那样,它将依赖属性附加到子元素上,我只想分隔依赖属性名称...
    • @JovanMeshkov:它是类型本身未定义的依赖属性。如果您想要一个带点的 DP 名称,这就是您必须完成的方法。期间。
    猜你喜欢
    • 2015-08-22
    • 2012-11-27
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    相关资源
    最近更新 更多