WPF - 如何判断ComboBox_SelectionChanged事件引发了什么

时间:2009-11-06 20:54:55

标签: c# wpf combobox selectionchanged

有没有办法告诉如何在WPF中引发ComboBox_SelectionChanged事件。

也就是说,事件是由于用户交互而引发的,还是由于绑定到的属性发生了变化?

3 个答案:

答案 0 :(得分:4)

在ComboBox.SelectionChanged事件中,发件人总是 ComboBox,SelectionChangedEventArgs中没有任何内容可以帮助您。

对我来说,有两种解决方法。您可以在绑定上使用转换器,或者您可以检查堆栈跟踪以查看System.Windows.Controls.Primitives.Selector.OnSelectedItemsCollectionChanged(object,NotifyCollectionChangedArgs)是否在堆栈中。堆栈检查非常难看,这是一种不好的做法,并且在部分信任环境中不起作用。所以我只会描述另一个。

在绑定上使用转换器来检测更改源

此解决方案相对干净,但需要更改绑定。当事情没有改变时,它有时会通知你。

步骤1:创建一个不进行转换但具有“已转换”事件和“ConvertedBack”事件的转换器:

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(例如,您正在使用附加属性),您仍然可以进入并在事后添加转换器。在这种情况下,您的转换器类将需要链接到先前声明的转换器,您将必须克隆Binding并安装新的(它们在使用后它们是不可变的),并且您还必须处理MultiBindings (如果你想支持他们)。

最后的注释

确定用户或财产是否进行更改的需要实际上可能是UI设计不佳的症状,通常是由于用户并不真正理解他们自己的要求。

我已经完成了几个项目,最终用户指定在“更改此ComboBox时”会发生这样的事情。几乎在所有情况下,事实证明应用程序在某些用例中会出现意外行为,我们找到了更好的方法来实现目标。在许多情况下,用户真正想要的是“当这个值首先与数据库中的值不同”或“当此值不再是默认值时”或“当此值为5时”。

答案 1 :(得分:2)

简答:不。应该没有区别,在两种情况下选择都发生了变化,这就是最重要的。 要确定它是否是用户交互,您必须监视其他事件的组合,如DropDownOpened / Closed和KeyDown / Up以及Stylus *。

答案 2 :(得分:1)

我也遇到了这种问题,并使用布尔bInternalChange变量解决了这个问题。

想象一个界面将°C转换为°F并返回两个ComboBox。选择第一个中的值会更新第二个中的值,而选择第二个中的值会更新第一个中的值。如果不区分UI更改和内部更改,它会创建一个无限循环。

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;
    }
}