Отмена операции привязки SourceUpdated в ComboBox - PullRequest
0 голосов
/ 13 марта 2012

Мой ComboBox:

<ComboBox
    SourceUpdated="MyComboBox_SourceUpdated"
    ItemsSource="{Binding ...}"
    SelectedValue="{Binding Path=SelectedValueMember, NotifyOnSourceUpdated=True}"
    SelectedValuePath="..."
    DisplayMemberPath="..."
/>

И мой SourceUpdated обработчик:

private void MyComboBox_SourceUpdated(object sender, DataTransferEventArgs args) {
    if (/* user answers no to an 'are you sure?' prompt */) {
        // TODO: revert ComboBox back to original value
    }
}

Мне трудно вернуть ComboBox к его первоначальному значению (в комментарии "TODO" моего кода выше).

Первая и самая очевидная вещь, которую я попытался, это просто изменить значение SelectedValueMember объекта DataContext, предполагая, что привязка обновит ComboBox:

MyDataContext.SelectedValueMember = original_value;

Когда я делаю это, в отладчике я вижу, что он действительно обновляет значение SelectedValueMember, но ComboBox не изменяется обратно - он сохраняет новое значение.

Есть идеи?


Ответ AngelWPF , приведенный ниже, работает и, вероятно, является самым аккуратным и ясным способом.

Однако я нашел неочевидное решение:

private void MyComboBox_SourceUpdated(object sender, DataTransferEventArgs args) {
    if (/* user answers no to an 'are you sure?' prompt */) {
        Dispatcher.BeginInvoke(new Action(() => {
            MyDataContext.SelectedValueMember = original_value;
        }));
    }
}

Просто поместив операцию во второй поток пользовательского интерфейса с помощью BeginInvoke, она работает! Я могу ошибаться, но моя догадка заключается в том, что во избежание связывания циклов обновления, действия непосредственно в обработчиках Обновление источника / цели не реагируют на привязки.

Ответы [ 2 ]

3 голосов
/ 22 марта 2012

Добавление к ответу AngelWPF с использованием UpdateSourceTrigger = "Explicit":

Несколько более чистый способ сделать это - использовать методы BindingExpression.UpdateSource () и BindingExpression.UpdateTarget ().UpdateSource () перемещает значение из элемента управления пользовательского интерфейса в ViewModel, а UpdateTarget () перемещает данные в противоположном направлении.Использование этих методов избавляет вас от необходимости выполнять следующую строку кода:

((MyObject) bndExp.DataItem).MyID = (int)((ComboBox) sender).SelectedValue;

Вопреки опыту AngelWPF, в моей ситуации мне пришлось возвращать ComboBox обратно к исходному значению, когдапользователь отменил, даже если для Binding.UpdateSourceTrigger было установлено значение «Явный».Может быть, это из-за Telerik RadComboBox или, возможно, предыдущий комментарий был неправильным, я не могу сказать в настоящее время.Но в любом случае следующий, более легкий для чтения, код работает.

private void OfficeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var comboBox = (RadComboBox) sender;
    var binding = comboBox.GetBindingExpression(RadComboBox.SelectedValueProperty);

    if(MessageBox.Show("Are you sure?", "Are you sure?", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
    {
        binding.UpdateSource();
    }
    else
    {
        binding.UpdateTarget();
    }
}

При необходимости добавьте свои собственные нулевые проверки.

2 голосов
/ 13 марта 2012

Для явного условного обновления источника в привязке используйте триггер обновления источника как Явный и обработайте событие изменения выбора в выпадающем списке, чтобы выполнить синхронизацию с источником на основерезультат окна сообщения.

    <StackPanel DataContext="{StaticResource MyObject}">
      <ComboBox ItemsSource="{Binding MyData}" 
             DisplayMemberPath="Name" 
             SelectedValuePath="ID"
             SelectedValue="{Binding Path=MyID,
                                     Mode=TwoWay,
                                     UpdateSourceTrigger=Explicit}"
             SelectionChanged="ComboBox_SelectionChanged">
      </ComboBox>
      <TextBlock Text="{Binding Path=MyID}"/>
    </StackPanel>

Таким образом, ComboBox привязан к коллекции элементов (называемых MyData), имеющих Name и ID в качестве свойств.Выбранное значение ComboBox связано с другим свойством с именем MyID.Теперь обратите внимание, что UpdateSourceTrigger=Explicit в привязке SelectedValue.

Способ синхронизации MyID при изменении выбора, ТОЛЬКО с выбранным значением в выпадающем списке, ТОЛЬКО если пользователь выбирает Yes в окне сообщениякак показано ниже ...

    private void ComboBox_SelectionChanged
      (object sender, SelectionChangedEventArgs e)
    {
        var bndExp
            = BindingOperations.GetBindingExpression(
                (ComboBox) sender, Selector.SelectedValueProperty);
        if (bndExp != null && bndExp.ParentBinding != null)
        {
            if (MessageBox.Show(
                  "Are you sure?",
                  "Sure?",
                  MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                ((MyObject) bndExp.DataItem).MyID
                    = (int)((ComboBox) sender).SelectedValue;
            }
        }
    }

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

...