Как я могу создать собственное * свойство только для записи * зависимости? - PullRequest
4 голосов
/ 22 августа 2009

Мне нужно знать, какова процедура для создания свойства зависимости только для записи. Я вижу, что класс DependencyProperty не имеет специального метода «Register» для свойств только для записи, но я не знаю, может ли метод RegisterAttached применяться к тому, что я пытаюсь сделать.

Это свойство должно быть свойством зависимости, а не простым свойством CLR. Внутренне мой класс требует PropertyChangedCallback для этого свойства, чтобы оставаться стабильным.

Я знаю, что могут быть созданы свойства зависимостей только для записи, потому что это довольно четко указано в:
Pro C # 2008 и платформа .NET 3.5, стр. 1061 .
Тем не менее, это единственное место, где я могу найти «свойство зависимости» и «только запись» на одной странице. И этот автор, по-видимому, не думал, что на самом деле необходимо показывать читателю процедуру для чего-либо, кроме базового свойства зависимости чтения-записи. Конечно, эта книга может быть грузом BS - но эта книга выглядит довольно стандартно, так что я думаю, что вполне уверенно, что автор прав. Я предполагаю, что недостаток информации в интернете проистекает из того факта, что вообще никому не нужно создавать такую ​​собственность.

Я знаю, звучит очень сомнительно, если вы хотите создать собственное свойство зависимости только для записи. Уверяю вас, имеет смысл, где я этого хочу. У моего класса есть свойство, значение которого полезно только для объекта, его устанавливающего. Если бы другой объект позже запросил значение этого свойства, он не смог бы иметь никакого рационального смысла в значении, не зная оригинального контекста установщика.

Это свойство не предназначено для использования в информационных целях. Разрешение сторонним объектам пытаться использовать значение свойства таким способом проблематично, опасно и представляет угрозу безопасности. Поэтому я считаю, что лучший дизайн - запретить операции чтения для этого свойства. Любой, кто использует мой класс, обнаружит, что он вынужден использовать класс так, как он задумывался, что в итоге получится намного лучше и чище.

Ответы [ 4 ]

4 голосов
/ 25 августа 2009

Вы не можете, это похоже на дизайн. Хотя я понимаю ваш подход к упомянутой книге и никоим образом не подвергаю сомнению ее качество, я все же предполагаю, что это какая-то проблема копирования и вставки или аналогичная проблема. Вот мои рассуждения:

Код системы свойств WPF

Проект системы свойств WPF

  • Более важно, 'Текущая реализация WPF своего XAML-процессора по своей природе осведомлена о свойстве зависимостей. Процессор WPF XAML использует системные методы свойств для свойств зависимостей при загрузке двоичного XAML и обработке атрибутов, которые являются свойствами зависимостей. Это эффективно обходит свойства оболочки. ', см. Свойства загрузки и зависимости XAML .
  • Самое главное, 'Свойства зависимости обычно следует рассматривать как открытые свойства. Природа системы свойств Windows Presentation Foundation (WPF) не позволяет создавать гарантии безопасности для значения свойства зависимости. ', см. Безопасность свойства зависимости .

В частности, последние две точки обозначают ограничение проекта: значения свойств зависимости всегда доступны через GetValue () / SetValue () , независимо от того, имеют ли доступ к их оболочкам CLR ограничен или доступен вообще, с единственным исключением, специально учитываемым Свойства зависимости только для чтения .

Следовательно, как и Jeffs , ответ уже подразумевает, что, например, простое удаление геттера на самом деле не мешает кому-либо получить доступ к свойству через GetValue () , хотя это может быть как минимум 'уменьшить сразу открытое пространство имен пользовательского класса' . Полезность любого такого семантического обходного пути, заключающегося в том, чтобы сделать значение свойства несколько менее видимым / доступным, а извлеченное значение по своей сути бесполезным для клиентов, как предлагает Джефф , конечно, зависит от вашего конкретного сценария.

2 голосов
/ 22 августа 2009

Интересно, что это определенно редкий сценарий, мне было бы интересно узнать больше о том, что он дает.

Рассматриваете ли вы идею предоставления недопустимого значения (например, null) для чтения через привязку или GetValue, в то время как просто нет получателя CLR?

Либо используйте частное свойство 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);
    }
0 голосов
/ 12 июня 2014

Похоже, вы можете использовать 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;
}

Обработчик приведения может быть удален с помощью замены метаданных, поэтому он не обеспечивает безопасности , но он не позволит разработчикам случайно создать соединение неправильным образом.

0 голосов
/ 25 августа 2009

Меня смущает, почему вы не можете просто заставить 'get' вернуть ничего полезного?

Но, кроме того, возможно, вы просто не реализуете OnMyWriteOnlyDependencyPropertyPropertyChanged, в примере Джеффа.

Нет реальной причины иметь событие, если никто не может его прочитать, верно?

...