В .NET 4.0 привязка OneWayToSource

OneWayToSource .NET 4.0 OneWayToSource

У меня есть эта простая часть Xaml

   

И мой код выглядит так

 public MainWindow() { InitializeComponent(); this.DataContext = this; } private string m_textProperty; public string TextProperty { get { return "Should not be used in OneWayToSource Binding"; } set { m_textProperty = value; } } 

В .NET 3.5 это работает, как вы могли бы исключить. Поместите некоторый текст в TextBox , нажмите Tab, чтобы он потерял Focus, а TextProperty обновляет любой текст, который был введен в TextBox

В .NET 4.0 , если я TextProperty текст в TextBox а затем нажмите Tab, чтобы потерять Focus, TextBox вернется к значению TextProperty (что означает «Не следует использовать в привязке OneWayToSource» ). Это перечитывание предназначено для OneWayToSource в .NET 4.0? Я просто хочу, чтобы TextBox подталкивал свое значение в TextProperty а не наоборот.

Обновить
Добавление Bounty к этому вопросу, поскольку это стало неудобством мэра в моем проекте, и я хотел бы знать причину, по которой это изменилось. Кажется, что get вызывается после того, как Binding обновил источник. Является ли это желаемым поведением для OneWayToSource Binding в .NET 4.0?

Если да

  • В чем была проблема с тем, как он работал в версии 3.5?
  • В каких сценариях это новое поведение лучше?

Или это на самом деле ошибка, которую мы можем надеяться зафиксировать в будущей версии?

В блоге Карла Шиффлетта и в ответе @ Simpzon уже рассказывается, почему они добавили эту функцию и почему это не проблема для свойств, которые всегда получают то, что было установлено. В вашем собственном коде вы всегда используете промежуточное свойство, которое имеет надлежащую семантику для привязки и использует внутреннее свойство, которое имеет семантику, которую вы хотите. Я бы назвал промежуточное свойство «блокирующим», потому что он блокирует getter от вашего внутреннего свойства.

Но в том случае, если у вас нет доступа к исходному коду для объекта, на который вы устанавливаете свойство, и вы хотите старое поведение, вы можете использовать конвертер.

Вот блокирующий конвертер с состоянием:

 public class BlockingConverter : IValueConverter { public object lastValue; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return lastValue; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { lastValue = value; return value; } } 

и вы можете использовать его для своего примера следующим образом:

          

Обратите внимание, что, поскольку у конвертера есть состояние, вам нужен отдельный экземпляр каждый раз, когда используется ресурс, и для этого мы можем использовать атрибут x:Shared="False" на ресурсе.

Это действительно по дизайну. Как правило, это не должно беспокоить, но, по вашему мнению, реализация вашей собственности, по крайней мере, нестандартная. Getters и seters (accessors) должны действительно быть не намного больше, чем получать и устанавливать, и каждый get должен соответствовать последнему соответствующему набору. (извините, нет источника для этого, это то, что мы назвали хорошим гражданством во всех командах разработчиков, в которых я был).

Подробнее об этой функции можно найти здесь: http://karlshifflett.wordpress.com/2009/05/27/wpf-4-0-data-binding-change-great-feature/

Ошибка, определенно.

если это «особенность», это очень плохо …

кажется, что они добавили вызов функции get () после выполнения set (), даже в режиме OneWayToSource … может ли кто-нибудь объяснить, почему?

также, спасибо, что указали это, это объясняет проблему, с которой я столкнулся с тех пор, как обновил свой проект до .net 4.0 и что я не мог объяснить до сих пор …

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

Это, безусловно, ошибка. Кажется, что кто-то сообщил хотя бы один раз. https://connect.microsoft.com/VisualStudio/feedback/details/612444/onewaytosource-broken-in-net-4-0

Я согласен со многими другими, что один из способов должен быть одним из способов.

Мой сценарий сложный, и функциональность, измененная между версиями каркаса, вызвала у меня настоящую головную боль.

У меня есть текстовое поле, привязанное к свойству. У меня есть конвертер, который меняет формат на лету. EG: Я ввожу EU5 в текстовое поле, свойство получает EU005. У меня есть набор привязки, который запускается при изменении свойства, поскольку мне нужно выполнять поиск в ViewModel по типу пользователя. Новая реализация изменяет значение текстового поля по мере ввода. Поэтому, если я хочу набрать EU512, я не мог бы легко, так как текст текстового поля продолжал бы меняться.

Я пробовал много вещей – Явное связывание (где вы решаете, когда обновлять и каким образом.) У этой проблемы есть та же проблема. Если я скажу, UpdateSource, он делает, но также затем перечитывает свойство и изменяет цель тоже.

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

Если бы MS сделала привязку так, как она логически названа, моя проблема исчезнет. Даже свойство на привязку к отказу от реализации .net4 и вести себя как 3.5 будет работать для меня.

У кого-нибудь есть предложения по поводу того, как я могу обойти это?

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

Мое решение блокирует повторное чтение свойства резервного копирования, но будет обновлять пользовательский интерфейс, когда он будет изменен каким-либо другим источником. Я основывал свое решение на блокирующем конвертере в ответе Рика Слэдки.

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

 public class MyConverter : IValueConverter { public object lastValue; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (LastValue != null && MyConvertBack(LastValue).Equals(value)) return lastValue; else return MyConvert(value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { lastValue = value; return MyConvertBack(value); } private object MyConvertBack(Object value) { //Conversion Code Here } private object MyConvert(Object value) { //Conversion Code Here } } 

В моем конкретном случае для этого у меня был суффикс длины и размера, хранящийся в текстовом поле (10 м, 100 мм и т. Д.). Преобразователь проанализировал это на двойное значение или добавил суффикс (в зависимости от направления преобразования). Без конвертера он добавит суффикс для каждого обновления текстового поля. Попытка ввести «10» приведет к «1m0», так как конвертер будет работать после первого нажатия клавиши.

Является ли это желаемым поведением для OneWayToSource Binding в .NET 4.0?

Да. Это делается для способности разработчика изменять предоставленную стоимость без неуклюжих конвертеров.

В чем была проблема с тем, как он работал в версии 3.5?

Нет проблем. Способ, которым он работал в 3.5, не позволял исправлять предоставленные значения.

В каких сценариях это новое поведение лучше?

Когда вам нужно исправить предоставленные значения. Если вам это не нужно, тогда вы должны просто написать правильный getter и setter.

 public string TextProperty { get; set; } 

Однако, как я вижу, изменение UpdateSourceTrigger на «PropertyChanged» сохраняет значения от перечитывания (чтобы вы могли оставить объявление старой собственности):

     private string m_textProperty; public string TextProperty { get { return "Should not be used in OneWayToSource Binding"; } set { m_textProperty = value; } } 
  • Ранняя и поздняя привязка
  • Конфликты Datacontext
  • WPF: привязать DataGrid к списку
  • Связанное с WPF привязка данных свойств
  • Ошибка WPF: не удается найти управляющий элемент FrameworkElement для целевого элемента
  • Как связать List с элементом управления DataGridView?
  • когда вызывается цикл $ digest?
  • Связывание WPF DataGrid с DataTable с использованием TemplateColumns
  • MVVM: привязка переключателей к модели просмотра?
  • Список vs BindingList Преимущества / Недостатки
  • Как я могу зарегистрировать глобальный настраиваемый редактор в Spring-MVC?
  • Давайте будем гением компьютера.