Разбирался с Coercion в биндинге WPF, и наткнулся на
старую темуАвтор:
Дата: 21.07.09
. Попытался разобраться и ответить на вопрос "баг или фича?"
Оказывается, фича, обеспечивающая отсутствие зацикливаний при смене значений зависимых свойств (dependency properties).
Да вот, собственно, я даже нарисовал (см. ниже). Еще подумал, что было бы, если бы CLR-property у ТС той темы получал бы уже Coerced Value. Был бы "плохой дизайн"
Тоже его нарисовал. Т.е. устойчивость биндинга обеспечивается тем, что у любого DependecnyProperty может быть только один источник. А т.к. этот источник может быть другим DependencyProperty со своим CoerceValueCallback'ом, то возникает проблема зацикливания биндинга. Вот и объяснение.
Прикрепил еще проектик по теме. Только я убрал DataContext'ный объект с CLR-property — ни при чем он здесь
Заменил TextBox'ами. В общем, в проекте этот эффект сразу виден, кому надо скачает и посмотрит, здесь код приводить не буду.
Вот картинка:
А в доказательство того, что Window.TextBox2 может влиять на то, что будет записано в Window.TextBox1, несмотря на то, что Window.TextBox1 привязан к UserControl.Value как к источнику,
вот еще более интересный проект со строками. Надо вбить что-нибудь в UserControl.TextBox2, нажать Tab, чтобы сместился фокус, и увидеть, что в Window.TextBox2 будет то, что вы набрали + 2 звездочки, а во всех остальных TextBox'ах + 3 звездочки, хотя в UserControl.Value_Coerce_Shared стоит + "*".
Секрет в том, что Window.TextBox2 является MyTextBox'ом, который я унаследовал от стандартного TextBox'а и сделал ему OverrideMetadata, где добавляю 2 звездочки. В итоге, в UserControl.TextBox2 после смены фокуса возвращается то, что вы набрали + 1 + 2 = +3 звездочки!
Вот определение MyTextBox:
public class MyTextBox : TextBox
{
public MyTextBox()
{
TextProperty.OverrideMetadata(typeof(MyTextBox), new FrameworkPropertyMetadata("This is MyTextBox's default value",
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
Text_Changed_Shared, Text_Coerce_Shared));
}
static void Text_Changed_Shared(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
static object Text_Coerce_Shared(DependencyObject d, object baseValue)
{
return (string)baseValue + "**";
}
}