代码之家  ›  专栏  ›  技术社区  ›  Giffyguy

如何创建自定义*只写*依赖项属性?

  •  4
  • Giffyguy  · 技术社区  · 15 年前

    我需要知道生成只写依赖属性的过程是什么。我可以看到DependencyProperty类没有用于只写属性的特殊“Register”方法,但我不知道RegisterAttached方法是否适用于我正在尝试的操作。

    此属性必须是依赖属性,而不是简单的clr属性。在内部,我的类需要此属性上的PropertyChangedCallback才能保持稳定。

    我知道可以创建只写依赖项属性,因为它在以下内容中有很清楚的说明:
    Pro C# 2008 and the .NET 3.5 Platform, Page 1061 .
    但是,这是我在同一页上唯一能找到“依赖属性”和“只写”的地方。显然,作者认为除了基本的读写依赖属性之外,没有必要向读者展示其他任何内容的过程。当然,这本书 能够 这本书看起来很标准,所以我认为作者是对的,这是一个相当安全的赌注。我认为互联网上缺乏信息是因为没有人通常需要这样的财产。

    我知道,想要创建自己的只写依赖属性听起来很可疑。我向你保证在我想要的地方它是有意义的。我的类有一个属性,该属性的值只对设置它的对象有用。如果另一个对象稍后请求该属性的值,那么在不了解setter的原始上下文的情况下,它将无法对该值做出任何合理的解释。

    此属性不用于信息目的。让外部对象以这种方式尝试使用属性值是有问题的、危险的,并且存在安全风险。所以我认为最好的设计是禁止对这个属性执行读取操作。任何使用我的类的人都会发现他们被迫按照预期的方式使用类,这最终会得到更好、更干净的结果。

    4 回复  |  直到 10 年前
        1
  •  4
  •   Community Dan Abramov    7 年前

    你不能,这似乎是故意的。虽然我能理解你对所提到的书的处理方法,而且我决不会质疑它的质量,但我仍然认为这是某种复制粘贴或类似的问题。我的理由是:

    WPF属性系统代码

    WPF物业系统设计

    • 更重要的是, '其XAML处理器的当前WPF实现本身具有依赖属性意识。WPF XAML处理器在加载二进制XAML和处理属于依赖属性的属性时,将属性系统方法用于依赖属性。这有效地绕过了属性包装器。 XAML Loading and Dependency Properties .
    • 最重要的是, '依赖属性通常应视为公共属性。Windows演示基础(WPF)属性系统的性质阻碍了对依赖性属性值进行安全性保证的能力。 Dependency Property Security .

    尤其是后两点概述了设计约束,依赖属性值总是可以通过 GetValue() / SetValue() ,无论其clr包装器是受访问限制还是完全可用,唯一的例外是 只读依赖项属性 .

    因此,作为 Jeffs 答案已经暗示了,例如删除getter并不能真正阻止任何人通过 获取值() 尽管这至少可以 '减少自定义类的立即公开的命名空间' . 任何这样的语义解决方法的有用性,即使属性值变得不那么可见/不可访问,并且检索到的值对于客户机来说本质上是无用的,正如 Jeff 当然,这取决于你的具体情况。

        2
  •  2
  •   Jeff Wilcox    15 年前

    有趣的是,这绝对是一个罕见的场景,我会有兴趣听到更多关于它的功能。

    您是否会考虑在没有clr getter的情况下,为读取绑定或getValue提供一个无效的值(如null)?

    或者使用私有DependencyProperty来存储您关心的“真实”值, 只是一个私有成员变量。

    在属性更改回调中,始终将值还原回原始值,同时存储已设置的新值。

    我现在大部分时间都花在开发Silverlight控件上,所以这个属性在WPF和Silverlight土地上工作,并且不使用胁迫或任何类似的乐趣。也许这会让你走上正轨。

        /// <summary>
        /// Sets the write-only dependency property.
        /// </summary>
        public string MyWriteOnlyDependencyProperty
        {
            set { SetValue(MyWriteOnlyDependencyPropertyProperty, value); }
        }
    
        private string _theRealSetValue;
    
        private bool _ignorePropertyChange;
    
        /// <summary>
        /// Identifies the MyWriteOnlyDependencyProperty dependency property.
        /// </summary>
        public static readonly DependencyProperty MyWriteOnlyDependencyPropertyProperty =
            DependencyProperty.Register(
                "MyWriteOnlyDependencyProperty",
                typeof(string),
                typeof(TemplatedControl1),
                new PropertyMetadata(null, OnMyWriteOnlyDependencyPropertyPropertyChanged));
    
        /// <summary>
        /// MyWriteOnlyDependencyPropertyProperty property changed handler.
        /// </summary>
        /// <param name="d">TemplatedControl1 that changed its MyWriteOnlyDependencyProperty.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnMyWriteOnlyDependencyPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TemplatedControl1 source = d as TemplatedControl1;
            if (source._ignorePropertyChange)
            {
                source._ignorePropertyChange = false;
                return;
            }
            string value = e.NewValue as string;
    
            source._theRealSetValue = value;
    
            // Revert, since this should never be accessible through a read
            source._ignorePropertyChange = true;
            source.SetValue(e.Property, e.OldValue);
        }
    
        3
  •  0
  •   Ben Voigt Caesar    10 年前

    看起来你可以用 CoerceValueCallback 通过 FrameworkPropertyMetadata 在依赖属性定义中应用。只需安装一个回调,它接受第二个参数(新值)并通过自己的只写机制将其传递给对象,然后返回 null (对于值类型, default(T) )

    确实“.net在强制之前会记住原始值”,但不会通过数据绑定进行传播。呼吁 GetValue 将返回强制值,该值不会泄漏任何内容。

    我使用它来实现我的主属性值的单向方便设置器,它是一个字节序列。例如,用户可以绑定一个字符串,将主属性设置为编码的字节(ASCII或UTF-8,具体取决于设置的属性)。但并非所有的字节序列都是有效的UTF-8,因此不可能反转转换并通过便利属性读取字符串。

    public string AsciiData
    {
        set { BinaryArray = Encoding.ASCII.GetBytes(value); }
    }
    
    public static readonly DependencyProperty AsciiDataProperty =
        DependencyProperty.Register("AsciiData",
            typeof(string),
            typeof(HexView),
            new FrameworkPropertyMetadata(null, CoerceAsciiData));
    
    private static object CoerceAsciiData(DependencyObject target, object value)
    {
        (target as HexView).AsciiData = value as string;
        return null;
    }
    

    可以通过元数据替换来删除强制处理程序,因此这不提供 安全 但它将防止开发人员以错误的方式意外创建耦合。

        4
  •  -1
  •   Noon Silk    15 年前

    我不明白为什么你不能只得到“得到”就没有什么有用的东西?

    但是,在Jeff的示例中,也许您没有实现“onMyWriteOnlyPendencyPropertyChanged”。

    如果没有人能读懂的话,没有真正的理由去做这件事,对吧?