WPF - Как сказать, что подняло событие combobox_selectionChanged

StackOverflow https://stackoverflow.com/questions/1690371

Вопрос

Есть ли способ сказать, как было поднято событие ComboBox_SelectionChanged в WPF.

То есть было ли событие повышено в результате взаимодействия с пользователем или в результате изменения в свойстве, которое он связан?

Это было полезно?

Решение

В событии ComboBox.SelectionChanged отправитель всегда Combobox и ничего в SelectionChangeDeventargs, что поможет вам.

Два решения для этого приходится мне. Вы можете использовать преобразователь на привязке, или вы можете проверить трассировку стека, чтобы увидеть, есть ли System.windows.controls.primitives.selector.SelectedItemsCollectionChanged (Object, notifyCollectionChangEdargs) находится в стеке. Проверка стека чрезвычайно уродлива, плохая практика и не будет работать в частичной доверительной среде. Так что я опишу только другой.

Использование преобразователя на привязке для обнаружения источников изменений

Это решение относительно чистое, но требует изменения в связующем. Это также иногда уведомляет вас, когда что -то не изменилось.

Шаг 1: Создайте преобразователь, который не делает преобразование, но имеет «преобразованное» событие и событие «конвертированного»:

public EventingConverter : IValueConverter
{
  public event EventHandler Converted;
  public event EventHandler ConvertedBack;

  public object Convert(object value, ...)
  {
    if(Converted!=null) Converted(this, EventArgs.Empty);
    return value;
  }
  public object ConvertBack(object value, ...)
  {
    if(ConvertedBack!=null) ConvertedBack(this, EventArgs.Empty);
    return value;
  }
}

Шаг 2: Установите привязку для использования нового экземпляра этого преобразователя (не делитесь экземплярами конвертера, используя словарь ресурсов или статическое свойство, как обычно выполняется)

<ComboBox ...>
  <ComboBox.SelectedValue>
    <Binding Path="..." ...>
      <Binding.Converter>
        <local:EventingConverter
          Converted="ComboBoxSelectedValue_Converted"
          ConvertedBack="ComboBoxSelectedValue_ConvertedBack" />
      </Binding.Converter>
    </Binding>
  </ComboBox.SelectedValue>
</ComboBox>

Теперь ваши методы ComboBoxSelectedValue_Converted и ComboBoxSelectedValue_ConvertedBack будут вызваны из процесса связывания.

ПРЕДУПРЕЖДЕНИЕ: Если вы бросите исключение в этих событиях, вы сломаете обязательство.

Если вы не можете изменить XAML, который делает привязку

Если у вас нет контроля над XAML, который создает привязку (например, вы используете прикрепленные свойства), вы все равно можете входить и добавить преобразователь после факта. В этом случае ваш класс преобразователя должен будет цепляться до ранее объявленного конвертера, вам придется клонировать привязку и установить новую (они неизбежны после их использования), и вам также придется иметь дело с многочисленными многоборьями (Если вы хотите их поддержать).

Заключительная примечание

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

У меня было несколько проектов, над которыми я работал, где конечный пользователь указал, что такой-то должен произойти, «когда я меняю этот комбо». Практически в каждом случае оказалось, что приложение было бы неожиданно вести себя в определенных случаях использования, и мы нашли лучший способ достижения цели. Во многих случаях пользователь действительно хотел «когда это значение сначала отличается от той в базе данных» или «когда это значение больше не по умолчанию» или «всякий раз, когда это значение составляет 5».

Другие советы

Короткий ответ: нет. Не должно быть разницы, в обоих случаях выбор изменился, это все, что имеет значение. Чтобы определить, было ли это взаимодействие с пользователем, вам придется отслеживать комбинацию других событий, таких как Dropdownopened/закрытый и Keydown/up, и стилус*.

Я также столкнулся с такой проблемой и решил ее с помощью логического bInternalChange переменная.

Представьте себе, что раздела интерфейс, преобразующий ° C в ° F и назад с двумя комбинированными. Выбор значения в первых обновлениях выбора второго и выбор значения во втором обновлении первым. Это создает бесконечную петлю, если вы не отличаете изменения пользовательского интерфейса от внутренних изменений.

bool bInternalChange = false;
private void ComboBoxF_SelectionChanged(...)
{
    if (!bInternalChange)
    {
        bInternalChange = true;
        ComboBoxC.SelectedValue = ConvertFtoC(...);
        bInternalChange = false;
    }
}
private void ComboBoxC_SelectionChanged(...)
{
    if (!bInternalChange)
    {
        bInternalChange = true;
        ComboBoxF.SelectedValue = ConvertCtoF(...);
        bInternalChange = false;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top