4

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

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

我知道可以创建只写依赖属性,因为它在
Pro C# 2008 and the .NET 3.5 Platform, Page 1061中有非常清楚的说明。
但是,这是我什至可以在同一页面上找到“依赖属性”和“只写”的唯一地方。而且这位作者显然认为没有必要向读者展示除了基本的读写依赖属性之外的任何程序。当然,这本书可能是一堆废话——但这本书看起来很标准,所以我认为作者是正确的可以肯定。我认为互联网上信息的缺乏源于这样一个事实,即通常没有人需要制作这样的房产。

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

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

4

4 回答 4

4

你不能,这似乎是设计使然。虽然我可以理解您对上述书籍的处理方法,并且绝不会质疑它的质量,但我仍然认为这是某种复制粘贴或类似问题。这是我的推理:

WPF 属性系统代码

WPF属性系统设计

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

特别是后两点概述了设计约束,依赖属性值始终可以通过GetValue() / SetValue()访问,无论它们的 CLR 包装器是访问受限还是完全可用,唯一的例外是特别说明只读依赖属性

因此,正如Jeffs的回答已经暗示的那样,例如,仅删除 getter 并不能真正阻止任何人通过GetValue()访问该属性,尽管这至少可以“减少自定义类的立即暴露的命名空间”正如Jeff所建议的那样,使属性值在某种程度上不那么可见/可访问以及检索到的值对客户来说本来就无用的任何此类语义解决方法的有用性当然取决于您的特定场景。

于 2009-08-25T00:12:42.503 回答
2

有趣的是,这绝对是一种罕见的情况,我很想听到更多关于它的功能。

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

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

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

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

    /// <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);
    }
于 2009-08-22T05:26:53.317 回答
0

看起来您可以通过依赖属性定义中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;
}

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

于 2014-06-12T17:30:58.300 回答
-1

我很困惑为什么你不能让'get'返回没有用的东西?

但此外,在 Jeff 的示例中,您可能只是没有实现“OnMyWriteOnlyDependencyPropertyPropertyChanged”。

如果没有人可以阅读它,就没有真正的理由来举办这个活动,对吧?

于 2009-08-25T00:47:02.607 回答