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

时间:2009-08-22 05:07:18

标签: .net .net-3.5 dependency-properties writeonly

我需要知道创建只写依赖项属性的过程是什么。我可以看到DependencyProperty类没有针对只写属性的特殊“Register”方法,但我不知道RegisterAttached方法是否适用于我想要做的事情。

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

我知道可以创建只写依赖项属性,因为它在以下内容中说得很清楚:
Pro C# 2008 and the .NET 3.5 Platform, Page 1061
但是,这是我在同一页面上找到“依赖属性”和“只写”的唯一地方。而且这位作者显然认为没有必要向读者展示除基本读写依赖属性之外的任何其他过程。当然,这本书可能是BS的负载 - 但这本书看起来非常标准,所以我认为这是一个非常安全的选择是作者是正确的。我认为互联网上缺乏信息源于这样一个事实:没有人通常需要制作这样的房产。

我知道想要创建自己的只写依赖项属性听起来很可疑。我向你保证,在我想要的地方有意义。我的类有一个属性,其值仅对设置它的对象有用。如果另一个对象稍后要求此属性的值,则在不知道setter的原始上下文的情况下,它将无法从值中理解。

此属性不用于提供信息。让外部对象尝试以这种方式使用属性值是有问题的,危险的,并且存在安全风险。因此,我认为最好的设计是禁止对此属性进行读取操作。任何使用我班级的人都会发现他们被迫按照预期的方式使用课程,最终会更好更清洁。

4 个答案:

答案 0 :(得分:4)

你不能,这似乎是设计的。虽然我可以理解你对所提到的书的态度并且绝不质疑它的质量,但我仍然认为这是某种复制和粘贴或类似的问题。这是我的理由:

WPF属性系统代码

WPF属性系统设计

  • 更重要的是,'其XAML处理器的当前WPF实现本质上是依赖属性感知。在加载二进制XAML和处理作为依赖项属性的属性时,WPF XAML处理器将属性系统方法用于依赖项属性。这有效地绕过了属性包装器。',请参阅XAML Loading and Dependency Properties
  • 最重要的是,'依赖属性通常应被视为公共属性。 Windows Presentation Foundation(WPF)属性系统的性质阻止了对依赖项属性值进行安全保证的能力。',请参阅Dependency Property Security

特别是后两点概述了设计约束,依赖属性值总是可以通过GetValue() / SetValue()访问,无论他们的CLR包装器是访问限制还是可用,都是唯一的例外是具体考虑Read-Only Dependency Properties

因此,正如Jeffs回答所暗示的那样,仅删除getter并不会真正阻止任何人通过GetValue()访问该属性,尽管这可能至少'减少了直接暴露的命名空间自定义类。任何此类语义解决方法的有用性使得属性值在某种程度上不那么可见/可访问,并且Jeff建议的检索值对客户端本身无用取决于您当前的特定情况。

答案 1 :(得分:2)

有趣的是,这绝对是一种罕见的情况,我有兴趣听到更多内容。

您是否会考虑通过绑定或GetValue为读取提供无效值(如null),而只是没有CLR getter?

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

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

我现在大部分时间都在做Silverlight控件开发,所以这个属性在WPF和Silverlight-land中运行,并且不使用coercian或类似的任何有趣的东西。也许它会让你走上正确的轨道。

    /// <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);
    }

答案 2 :(得分:0)

看起来您可以通过依赖项属性定义中应用的CoerceValueCallback使用与属性关联的FrameworkPropertyMetadata。只需安装一个带有第二个参数的回调,即新值,通过您自己的只写机制将其传递给对象,然后返回null(或者对于值类型,default(T))。

确实&#34; .NET会记住强制之前的原始值&#34;但它不会通过数据绑定传播。致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;
}

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

答案 3 :(得分:-1)

我很困惑为什么你不能让'get'返回没什么用处?

但是,你可能只是在Jeff的例子中没有实现'OnMyWriteOnlyDependencyPropertyPropertyChanged'。

没有真正的理由参加活动,如果没有人可以阅读,对吧?

相关问题