public class DataType : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int _value;
public string Name { get; set; }
public int Value
{
get => _value;
set
{
_value = value;
Debug.WriteLine($"{Name} => {Value}");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
}
}
}
Вот такой workaround придумал, чтобы заставить вести себя TwoWay Binding как OneWayToSource Binding:
1) Создаем конвертер который "умеет" конвертировать только в направлении Target->Source:
[ValueConversion(typeof(string), typeof(int))]
public class StringToIntOneWayConverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
// Source -> Target (int -> string)public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Специально чтобы TextBox.Text сбрасывался в string.Emptyreturn DependencyProperty.UnsetValue;
}
// Target -> Source (string -> int) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if(targetType == typeof(int))
{
var stringValue = value as string;
if (string.IsNullOrEmpty(stringValue))
return Binding.DoNothing;
if (int.TryParse(stringValue, out int intValue))
return intValue;
}
return DependencyProperty.UnsetValue;
}
}
2) Изменяем тип привзяки для второго TextBox'а (там где NewValue) с OneWayToSource на TwoWay и прицепляем к привязке конвертер:
Здравствуйте, bkat, Вы писали:
B>Тебе нужен OneWay, а не OneWayToSource.
Нет, мне нужно чтобы изменения в TextBox.Text обновляли DataType.Value, но не наоборот. Поскольку TextBox.Text это Target, то мне нужно чтобы привязка работала только в направлении Target -> Source, и этот режим называется OneWayToSource. Цитирую вашу же ссылку:
OneWayToSource: This is the opposite of OneWay -- user interface value changes update the bound property.
:)
Re[3]: [WPF] Почему не работает Binding в режиме OneWayToSou
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, bkat, Вы писали:
B>>Тебе нужен OneWay, а не OneWayToSource.
C>Нет, мне нужно чтобы изменения в TextBox.Text обновляли DataType.Value, но не наоборот. Поскольку TextBox.Text это Target, то мне нужно чтобы привязка работала только в направлении Target -> Source, и этот режим называется OneWayToSource. Цитирую вашу же ссылку: C>
C>OneWayToSource: This is the opposite of OneWay -- user interface value changes update the bound property.
Ааа. теперь понял что ты хочешь.
Там проблема не в OneWayToSource, а в том, что байндишь на SelectedValue.Value.
Попробуй поставить SelectedIndex изначально и поиграйся. Тогда будет понятно.
А если ты стартуешь с невыбранным элепментов в комбобоксе, то у тебя SelectedValue.Value в самом начале неопределен и остается неопределнным,
посколько ты выбрал OneWayToSource.
А если укажешь Mode=TwoWay, то и без конвертера будет работать.
С конвертером у тебя "вдруг" заработало, потому что там у тебя Mode=TwoWay.
А вообще OneWayToSource больше используют в MVVM, где у тебя в модели есть куда нормально байндить.
А так между элементами view надо точно понимать что и когда существует.
Здравствуйте, bkat, Вы писали:
B>Попробуй поставить SelectedIndex изначально и поиграйся. B>А если ты стартуешь с невыбранным элепментов в комбобоксе, то у тебя SelectedValue.Value в самом начале неопределен и остается неопределнным, посколько ты выбрал OneWayToSource.
Ну даже если установить SelectedIndex Binding всё равно не сработает, хотя должен.
B>А если укажешь Mode=TwoWay, то и без конвертера будет работать.
Потому что дефолтный конвертер умеет вызывать ToString для стандартных типов данных, т.е. в принципе не нужен конвертер когда тебе надо int в String преобразовать. А я конвертер сделал, чтобы TwoWay Binding "переделать" в OneWayToSource Binding
B>С конвертером у тебя "вдруг" заработало, потому что там у тебя Mode=TwoWay.
У меня ни чего "вдруг" не работает, я целенаправленно искал решение проблемы и нашел.
B>Там проблема не в OneWayToSource, а в том, что байндишь на SelectedValue.Value.
Это-то понятно. Если например привязать тот-же TextBox к ComboBox.SelectedIndex, то будет работать как TwoWay, так и OneWayToSource.
:)
Re[5]: [WPF] Почему не работает Binding в режиме OneWayToSou
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, bkat, Вы писали:
C>Это-то понятно. Если например привязать тот-же TextBox к ComboBox.SelectedIndex, то будет работать как TwoWay, так и OneWayToSource.
TwoWay слушает события с обоих сторон, соответственно когда SelectedValue в комбобоксе изменилось то биндинг об этом узнал, обновил ссылку на объект и начал проталкивать
изменения в текущее SelectedValue комбобокса.
при OneWayToSource биндинг не слушает изменений в комбобоксе, поэтому он запомнил null при открытии формы и не обновляет эту ссылку, даже когда SelectedValue в комбобоксе изменилось
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, bkat, Вы писали:
B>>Попробуй поставить SelectedIndex изначально и поиграйся. B>>А если ты стартуешь с невыбранным элепментов в комбобоксе, то у тебя SelectedValue.Value в самом начале неопределен и остается неопределнным, посколько ты выбрал OneWayToSource.
C>Ну даже если установить SelectedIndex Binding всё равно не сработает, хотя должен.
Должно работать. Будет выбираться другой элемент комбобокса в зависимости от того, что ты введешь в TextBox.
Ну да ладно... Ситуация вроде прояснилась, а в реальном коде у тебя наверняка все немного сложнее.
Валидаторы там всякие, значения по-умолчанию и структуры данных сложнее.
А так вот врямо байндить на SelectedValue.Value я бы не стал.
intellisense не работает. Рефекторинг тоже рискованный если ты вдруг захочешь переименовать что.
Я бы завел SelectedItem в view model и плясал бы от него.
B>Должно работать. Будет выбираться другой элемент комбобокса в зависимости от того, что ты введешь в TextBox.
Должно но не работает, я сегодня проверял. С TwoWay работает, с OneWayToSource нет.
B>Ну да ладно... Ситуация вроде прояснилась, а в реальном коде у тебя наверняка все немного сложнее. B>Валидаторы там всякие, значения по-умолчанию и структуры данных сложнее.
Проблема в том, что не работает ни как, ни в учебном примере, ни в сложном.
:)
Re[6]: [WPF] Почему не работает Binding в режиме OneWayToSou
Здравствуйте, ksg71, Вы писали:
K>TwoWay слушает события с обоих сторон, соответственно когда SelectedValue в комбобоксе изменилось то биндинг об этом узнал, обновил ссылку на объект и начал проталкивать K>изменения в текущее SelectedValue комбобокса. K>при OneWayToSource биндинг не слушает изменений в комбобоксе, поэтому он запомнил null при открытии формы и не обновляет эту ссылку, даже когда SelectedValue в комбобоксе изменилось
А это ваше предположение или есть какой то официальный документ который это описывает?
:)
Re[7]: [WPF] Почему не работает Binding в режиме OneWayToSou
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, bkat, Вы писали:
B>>Должно работать. Будет выбираться другой элемент комбобокса в зависимости от того, что ты введешь в TextBox.
C>Должно но не работает, я сегодня проверял. С TwoWay работает, с OneWayToSource нет.
Не знаю, как оно там у тебя.
Специально не поленился.
Вот такой хaml работает.
Как только в TextBox_ComboBoxIndexSelectorнабираешь 0, в комбобоксе выбирается первый элемент и т.д...
Здравствуйте, Cynic, Вы писали:
C>Здравствуйте, ksg71, Вы писали:
K>>TwoWay слушает события с обоих сторон, соответственно когда SelectedValue в комбобоксе изменилось то биндинг об этом узнал, обновил ссылку на объект и начал проталкивать K>>изменения в текущее SelectedValue комбобокса. K>>при OneWayToSource биндинг не слушает изменений в комбобоксе, поэтому он запомнил null при открытии формы и не обновляет эту ссылку, даже когда SelectedValue в комбобоксе изменилось
C>А это ваше предположение или есть какой то официальный документ который это описывает?
Если тебя это на самом деле интересует, то ты даже в исходники WPF можешь глянуть.
Все работает как описал ksg71.
Ну или проще...
В дебагере посмотри на BindingExpression в твоем оригинальном text box и там все сразу понятно.
Re[8]: [WPF] Почему не работает Binding в режиме OneWayToSou
Здравствуйте, ksg71, Вы писали:
K>TwoWay слушает события с обоих сторон, соответственно когда SelectedValue в комбобоксе изменилось то биндинг об этом узнал, обновил ссылку на объект и начал проталкивать K>изменения в текущее SelectedValue комбобокса. K>при OneWayToSource биндинг не слушает изменений в комбобоксе, поэтому он запомнил null при открытии формы и не обновляет эту ссылку, даже когда SelectedValue в комбобоксе изменилось
В общем я тут вспомнил как дебажить Binding'и всё прояснилось:
// При загрузке формы:
System.Windows.Data Information: 41 : BindingExpression path error: 'Value' property not found for'object' because data item is null. This could happen because the data provider has not produced any data yet. BindingExpression:Path=SelectedValue.Value; DataItem='ComboBox' (Name='cmbName'); target element is'TextBox' (Name=''); target property is'Text' (type 'String')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=SelectedValue.Value; DataItem='ComboBox' (Name='cmbName'); target element is'TextBox' (Name=''); target property is'Text' (type 'String')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=SelectedValue.Value; DataItem='ComboBox' (Name='cmbName'); target element is'TextBox' (Name=''); target property is'Text' (type 'String')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=SelectedValue.Value; DataItem='ComboBox' (Name='cmbName'); target element is'TextBox' (Name=''); target property is'Text' (type 'String')
System.Windows.Data Warning: 56 : Created BindingExpression (hash=65445301) for Binding (hash=38376892)
System.Windows.Data Warning: 58 : Path: 'SelectedValue.Value'
System.Windows.Data Warning: 62 : BindingExpression (hash=65445301): Attach to System.Windows.Controls.TextBox.Text (hash=34090260)
System.Windows.Data Warning: 67 : BindingExpression (hash=65445301): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=65445301): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 : Lookup name cmbName: queried TextBox (hash=34090260)
System.Windows.Data Warning: 78 : BindingExpression (hash=65445301): Activate with root item ComboBox (hash=4152081)
System.Windows.Data Warning: 107 : BindingExpression (hash=65445301): At level 0 using cached accessor for ComboBox.SelectedValue: DependencyProperty(SelectedValue)
System.Windows.Data Warning: 104 : BindingExpression (hash=65445301): Replace item at level 0 with ComboBox (hash=4152081), using accessor DependencyProperty(SelectedValue)
System.Windows.Data Warning: 101 : BindingExpression (hash=65445301): GetValue at level 0 from ComboBox (hash=4152081) using DependencyProperty(SelectedValue): <null>
System.Windows.Data Warning: 106 : BindingExpression (hash=65445301): Item at level 1 is null - no accessor
System.Windows.Data Information: 41 : BindingExpression path error: 'Value' property not found for'object' because data item is null. This could happen because the data provider has not produced any data yet. BindingExpression:Path=SelectedValue.Value; DataItem='ComboBox' (Name='cmbName'); target element is'TextBox' (Name='txtNewValue'); target property is'Text' (type 'String')
System.Windows.Data Warning: 90 : BindingExpression (hash=65445301): Update - got raw value ''
System.Windows.Data Warning: 94 : BindingExpression (hash=65445301): Update - using final value ''
// При выборе любого элемента в ComboBox:
System.Windows.Data Information: 41 : BindingExpression path error: 'Name' property not found for'object' because data item is null. This could happen because the data provider has not produced any data yet. BindingExpression:Path=Name; DataItem=null; target element is'ComboBox' (Name='cmbName'); target property is'NoTarget' (type 'Object')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=Name; DataItem=null; target element is'ComboBox' (Name='cmbName'); target property is'NoTarget' (type 'Object')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=Name; DataItem=null; target element is'ComboBox' (Name='cmbName'); target property is'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Name; DataItem=null; target element is'ComboBox' (Name='cmbName'); target property is'NoTarget' (type 'Object')
Получается если нужно, чтобы можно было выбрав объект в cmbName изменять значение свойства SelectedValue.Value только в направлении OneWayToSource, то единственный способ это сделать только с помощью Binding'ов (не городя свойств в форме и т.п.) это: Включить режим привязки TwoWay, чтобы привязка следила за изменениями как в Source, так и в Target. OneWayToSource работать не будет, т.к. отслеживает изменения только в Target
Сделать конвертер который будет пропускать значения только в направления Target -> Source