Как я могу создать пользовательское свойство зависимости, доступное только для записи?

StackOverflow https://stackoverflow.com/questions/1315186

Вопрос

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

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

Я знаю, что свойства зависимостей только для записи могут быть созданы, потому что это довольно четко указано в:
Профессиональный C # 2008 и платформа .NET 3.5, Страница 1061.
Однако это единственное место, где я могу даже найти "свойство зависимости" и "только запись" на одной странице.И этот автор, очевидно, не считал необходимым на самом деле показывать читателю процедуру для чего-либо, кроме базового свойства зависимости чтения-записи.Конечно, эта книга мог бы полная чушь, но эта книга выглядит довольно стандартно, так что я думаю, можно с уверенностью сказать, что автор прав.Я предполагаю, что недостаток информации в Интернете связан с тем фактом, что обычно никому не нужно создавать подобное свойство.

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

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

Это было полезно?

Решение

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

Системный код свойства WPF

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

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

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

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

Другие советы

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

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

Либо используйте частное свойство DependencyProperty для хранения "реального" значения, о котором вы заботитесь, или просто закрытая переменная-член.

В обратном вызове property changed всегда возвращайте значение к исходному, сохраняя при этом новое значение, которое было установлено.

Сейчас я трачу большую часть своего времени на разработку элементов управления 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);
    }

Похоже, вы можете использовать CoerceValueCallback связанный с объектом недвижимости через FrameworkPropertyMetadata применяется в определении свойства зависимости.Просто установите обратный вызов, который принимает второй аргумент, новое значение, передает его объекту через ваш собственный механизм только для записи, затем возвращает null (или для типов значений, default(T)).

Это правда, что ".NET запоминает исходное значение до принудительного использования", но оно не будет распространяться через привязку данных.Призывает к GetValue вернет принудительное значение, которое ничего не пропускает.

Я использую это для реализации односторонних установщиков удобства для значения моего основного свойства, которое представляет собой последовательность байтов.Пользователь может привязать строку, например, для установки основного свойства к закодированным байтам (ASCII или UTF-8, в зависимости от того, какое свойство установлено).Но не все последовательности байтов являются допустимыми в формате UTF-8, поэтому невозможно отменить преобразование и прочитать строку обратно через свойство convenience .

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top