Зависимость Свойство Связывание и обновление настраиваемого элемента управления - он обновляется, но, по-видимому, не в обоих направлениях?

89
10

ViewModel:


public class MyViewModel : INotifyPropertyChanged
{
public string MyText { ... }
}

XAML:


<my:MySpecialTextBox Text="{Binding MyText}" />

Пользовательский контроль:


public class MySpecialTextBox : TextBox
{
static MySpecialTextBox()
{
TextProperty.OverrideMetadata(typeof(MySpecialTextBox),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
DefaultValue = string.empty,
PropertyChangedCallback = OnTextPropertyChanged
});
}

private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as MySpecialTextBox;

if (control != null)
{
control.Text = SomeAdjustedValue((string)e.NewValue);
}
}
}


Проблема заключается в том, что, хотя DependencyProperty в настраиваемом элементе управления правильно настраивается, он не обновляет ViewModel. Я понимаю, что это похоже на CoerceValueCallback из-за присвоения имени SomeAdjustedValue, но Coercion не изменяет значение ViewModel. Кажется, я не могу обновить значение в моей модели ViewModel, если это был триггер для обратного вызова OnTextPropertyChanged для начала... Я выполнил трассировку отладки и второй раз не просматривал ViewModel с новым значением. Не уверен, что делать, чтобы исправить это.

спросил(а) 2021-01-25T12:56:56+03:00 5 месяцев назад
1
Решение
108

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


Я думаю, вам нужно будет получить привязку на TextBox.Text и обновить исходный код, однако я бы не рекомендовал это делать, поскольку вы будете смешивать свой уровень бизнес-логики с вашим уровнем пользовательского интерфейса.

Если вы хотите, чтобы на дисплее появилось какое-то настраиваемое форматирование, я бы сделал это в конвертере, чтобы он фактически не изменил значение источника данных. Если вы хотите изменить фактическое значение источника данных, я бы сделал это с событием ViewModel PropertyChanged

ответил(а) 2021-01-25T12:56:56+03:00 5 месяцев назад
45

Отказ от ответственности сначала - это пахнет логикой, которая должна жить внутри ViewModel, а не в привязке UI.


Тем не менее, если вы настроены на это так, я думаю, что вам нужно сначала проверить, отличается ли значение "Скорректированное значение" от уже предоставленного (чтобы избежать циклизации бесконечно), затем используйте DependencyProperty.SetValue, чтобы установить значение свойства зависимости в элементе управления, а не просто установить его свойство Text.

ответил(а) 2021-01-25T12:56:56+03:00 5 месяцев назад
45

В FrameworkPropertyMetadata существуют различные конструкторы, которые вы можете использовать. Используйте его с параметром FrameworkPropertyMetadataOptions. Параметр FrameworkPropertyMetadataOptions.BindsTwoWayByDefault по умолчанию включает двустороннюю привязку, в противном случае это всего лишь один способ.


Изменить: Так вы и сделали, я должен перестать пытаться отвечать на вопросы, когда я болен.

ответил(а) 2021-01-25T12:56:56+03:00 5 месяцев назад
45

Вы пробовали это?


private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as MySpecialTextBox;

if (control != null)
{
control.SetCurrentValue(TextBox.TextProperty, SomeAdjustedValue((string)e.NewValue));
}
}

Метод SetCurrentValue() гарантирует, что привязка сохраняется, когда простой SetValue(), который вызывается под капотом, если вы используете средство настройки свойств Text, удалит привязку.

ответил(а) 2021-01-25T12:56:56+03:00 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема