Как я могу создать собственное * свойство только для записи * зависимости?
Мне нужно знать, какова процедура создания свойства зависимости только для записи. Я вижу, что класс DependencyProperty не имеет специального метода "Register" для свойств только для записи, но я не знаю, может ли метод RegisterAttached применяться к тому, что я пытаюсь сделать.
Это свойство должно быть свойством зависимости, а не простым свойством CLR. Внутренне мой класс требует PropertyChangedCallback для этого свойства, чтобы оставаться стабильным.
Я знаю, что могут быть созданы свойства зависимости только для записи, потому что это довольно четко указано в:
Pro C# 2008 и платформа.NET 3.5, стр. 1061.
Тем не менее, это единственное место, где я могу найти "свойство зависимости" и "только запись" на одной странице. И этот автор, по-видимому, не считал необходимым показывать читателю процедуру для чего-либо, кроме базового свойства зависимости чтения-записи. Конечно, эта книга могла бы быть грузом BS, но эта книга выглядит довольно стандартно, поэтому я думаю, что это довольно уверенная ставка, что автор прав. Я предполагаю, что недостаток информации в интернете проистекает из того факта, что вообще никому не нужно создавать такую собственность.
Я знаю, звучит очень сомнительно, если вы хотите создать собственное свойство зависимости только для записи. Уверяю вас, имеет смысл, где я этого хочу. У моего класса есть свойство, значение которого полезно только для объекта, его устанавливающего. Если бы другой объект позже запросил значение этого свойства, он не смог бы иметь никакого рационального смысла в значении, не зная оригинального контекста установщика.
Это свойство не предназначено для использования в информационных целях. Разрешение сторонним объектам пытаться использовать значение свойства таким способом проблематично, опасно и представляет угрозу безопасности. Поэтому я считаю, что лучший дизайн - запретить операции чтения для этого свойства. Любой, кто использует мой класс, обнаружит, что он вынужден использовать класс так, как он задумывался, что в итоге получится намного лучше и чище.
4 ответа
Вы не можете, это похоже на дизайн. Хотя я могу понять ваш подход к упомянутой книге и никоим образом не ставить под сомнение ее качество, я все же предполагаю, что это какая-то проблема копирования и вставки или аналогичная проблема. Вот мои рассуждения:
Код системы свойств WPF
- Как вы уже упоминали, общедоступный API класса DependencyProperty поддерживает только функции RegisterReadOnly() и RegisterAttachedReadOnly ().
- При произнесении слов во внутренние классы класса через Reflector выявляется только выделенный код для обработки этих свойств зависимостей только для чтения, в отношении функциональности только для записи ничего не видно.
- Другим вариантом могли бы быть метаданные, но ни метаданные свойства зависимостей, ни, в частности, метаданные свойства платформы с помощью перечисления Framework Property MetadataOptions не предоставляют ничего похожего на запись только для записи.
Проект системы собственности WPF
- Что еще более важно : "Текущая реализация WPF его процессора XAML по своей природе осведомлена о свойстве зависимостей. Процессор WPF XAML использует системные методы свойств для свойств зависимостей при загрузке двоичного XAML и атрибутов обработки, которые являются свойствами зависимостей. Это эффективно обходит свойства оболочки. см. Свойства загрузки и зависимости XAML.
- Наиболее важным является то, что свойства зависимостей обычно следует рассматривать как общедоступные свойства. Природа системы свойств Windows Presentation Foundation (WPF) не позволяет создавать гарантии безопасности для значения свойства зависимости.' см. Зависимость свойства собственности.
Особенно последние две точки обрисовывают в общих чертах ограничение проекта, что значения свойств зависимости всегда доступны через GetValue () / SetValue (), независимо от того, являются ли их оболочки оболочки CLR ограниченными или доступными вообще, с единственным исключением, специально учитываемым Свойства зависимостей только для чтения.
Следовательно, как уже подразумевает ответ Джеффса, простое удаление, например, метода получения, на самом деле не мешает кому-либо получить доступ к свойству через GetValue (), хотя это может по крайней мере "уменьшить сразу же открытое пространство имен пользовательского класса". Полезность любого такого семантического обходного пути, заключающегося в том, чтобы сделать значение свойства несколько менее видимым / доступным, а извлеченное значение по своей сути бесполезным для клиентов, как предложил Джефф, конечно, зависит от вашего конкретного сценария.
Интересно, что это определенно редкий сценарий, мне было бы интересно узнать больше о том, что он дает.
Рассматриваете ли вы идею предоставления недопустимого значения (например, 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);
}
Похоже, вы можете использовать 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;
}
Обработчик приведения может быть удален путем замены метаданных, так что это не обеспечивает безопасность, но предотвратит случайное создание связи разработчиками неверным образом.
Я не понимаю, почему вы не можете просто вернуть 'get' ничего полезного?
Но, кроме того, возможно, вы просто не реализуете OnMyWriteOnlyDependencyPropertyPropertyChanged, в примере Джеффа.
Нет реальной причины для проведения мероприятия, если никто не может его прочитать, верно?