2012-03-23 2 views
0

При отладке проблемы в приложении WPF я заметил, что привязка данных TwoWay не кажется симметричной. Вот пример:Как получить симметричную привязку TwoWay?

<Window x:Class="ConverterTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:ConverterTest" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <local:TextConverter x:Key="textConverter"/> 
    </Window.Resources> 
    <Grid> 
     <TextBox x:Name="txt1" Height="24" Margin="0" VerticalAlignment="Top"/> 
     <TextBox x:Name="txt2" Height="24" Margin="0,40,0,0" VerticalAlignment="Top" 
       Text="{Binding ElementName=txt1, Path=Text, 
         Mode=TwoWay, 
         UpdateSourceTrigger=PropertyChanged, 
         Converter={StaticResource textConverter}}"/> 
    </Grid> 
</Window> 

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

public class TextConverter : IValueConverter 
{ 
    #region IValueConverter Members 

    public object Convert(object value, System.Type targetType, 
     object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value.ToString().ToUpper(); 
    } 

    public object ConvertBack(object value, System.Type targetType, 
     object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value.ToString().ToLower(); 
    } 

    #endregion 
} 

При редактировании внутри txt1 только Convert() называется; но при редактировании внутри txt2, сначала ConvertBack(), а затем Convert().

Другими словами, TwoWay связывание, кажется, работает так:

  • Если свойство источника обновляется, свойство цели обновляется.
  • Когда свойство target обновляется, сначала обновляется свойство source, а затем свойство target обновляется снова.

MSDN documentation просто говорит:

Причина изменения либо свойства источника или целевое свойство для автоматического обновления других.

Из этого предложения, я бы ожидал следующее поведение:

  • Если свойство источника обновляется, свойство цели обновляется.
  • Когда свойство target обновляется, свойство source обновляется.

Есть ли способ достичь этого симметричного поведения (только в XAML, без программирования на C#)?

EDIT: Я только что обнаружил, что в WPF 3.5, TwoWay крепления работают симметрично. Однако в WPF 4.0 поведение изменилось (как описано выше).

+0

Это поведение, на мой взгляд, согласуется с документацией. txt2 является источником самого себя - подумайте о последствиях, если это не так. Если вы хотите, чтобы txt2 не был источником, тогда привяжите его в будущем и используйте текстовый блок. – Paparazzi

+0

@Blam: Я думаю, что есть веские причины как для несимметричной, так и для симметричной привязки TwoWay. В моем примере выше, если вы вводите строчные буквы в txt2, они неожиданно преобразуются в верхние буквы внутри txt2 во время ввода. В этом конкретном примере это не имеет большого значения, но могут быть и другие, более сложные привязки (например, форматирование даты/времени), где пользователи, конечно, будут раздражаться, когда WPF переформатирует напечатанный текст. Этого можно легко избежать с помощью симметричной привязки TwoWay. –

+0

@Blam - Это легко избежать/выполнимо/решено путем отказа от требования «нет C#». –

ответ

2

Ну, полностью симметричны не может быть достигнуто, потому что:

  • Когда источник обновляется, управление просто должен показать новое значение, период. Ничего необычного не происходит.
  • Когда цель обновляется, прежде чем она будет записана в источник, изменение значения может быть отменено в смешном количестве мест.

Например: валидация.

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

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

Но, как вы видите, значение могло быть изменено между целью и источником, поэтому значение снова преобразуется и, наконец, отображается.

Бонус: чтобы понять, где и в каком порядке значение может измениться, см. Dependency Property Value Precedence.

+0

Вы пишете: «значение могло быть изменено между целью и источником» Именно поэтому я считаю, что должна быть возможность иметь симметричное связывание, так что преобразования, принуждения и проверки не отражаются обратно к цели , По общему признанию, в большинстве случаев текущее поведение WPF выглядит нормально, но есть случаи, когда это не так (см. Мой пример выше и мой комментарий к Blam). –

+0

Но если значения не отражаются на цели, то ваш источник имеет другое значение, чем цель. Это побеждает цель привязки! –

+0

Если вы не хотите, чтобы письмо было преобразовано в верхний регистр во время ввода пользователем, просто удалите «UpdateSourceTrigger = PropertyChanged», он по умолчанию вернется в «LostFocus», и преобразование произойдет, когда фокус удаляется. –

Смежные вопросы