【问题标题】:Getting 'ConvertBack(...)' to fire on WPF ComboBox selection change让“ConvertBack(...)”在 WPF ComboBox 选择更改时触发
【发布时间】:2011-05-11 17:39:20
【问题描述】:

我有一个ComboBox,其Items 属性绑定到一个对象集合。我还将SelectedItem 属性绑定到整个集合,ValueConverter 旨在检查集合中的元素并返回要选择的 1 个项目。这部分有效。

当用户在 ComboBox 上进行选择更改时不起作用,ValueConverterConvertBack(...) 方法不会被调用。我需要调用ConvertBack(...),因为我需要接受用户的选择,重新检查集合,并适当地编辑旧的选中项和新选中的项。

我知道这种方法很尴尬,但就是这样。以下是相关代码:

组合框:

<ComboBox ItemsSource="{Binding}" SelectedItem="{Binding Path=., Converter={StaticResource ResourceKey=DataInputAssetChoiceSelectedItemConverter}}" />

值转换器:

public class DataInputAssetChoiceSelectedItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            foreach (CustomObject Choice in (Collection<CustomObject>)value)
            {
                if (Choice.IsSelected)
                {
                    return Choice;
                }
            }
            return ((Collection<CustomObject>)value).First();
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {   //breakpoint...execution never gets here!
        return null;
    }
}

那么为什么ConvertBack(...) 从来没有被调用呢?这只是我对ComboBox 的误解吗?我尝试过使用SelectedItemSelectedValueSelectedIndex 的这种方法,并尝试使用UpdateSourceTrigger、各种绑定模式、DataTriggers,但似乎永远无法调用ConvertBack(...)。使用SelectionChanged 事件是唯一的选择吗?如果有,为什么?

【问题讨论】:

    标签: wpf combobox ivalueconverter


    【解决方案1】:

    您没有绑定到属性,因此 Binding 无法设置任何内容。您正在直接绑定到 DataContext 对象,而 Binding 不会更新它。

    如果您有{Binding Path=SomeProperty, Converter=...},则将调用 ConvertBack。就目前而言,它不会被调用。

    【讨论】:

    • 感谢这个花絮。基于这种行为,也许应该禁止使用 DataContext 作为 Binding 的源,因为它不能完全参与 Binding。我想我将不得不使用 SelectionChanged 事件并从那里编辑 DataCollection 的内容。要么改变数据模型,所以我可以绑定到一个实际的属性......但这会很可怕。
    • 标记为答案,因为您解释了为什么 ConvertBack(...) 不适用于这种特殊情况。谢谢。
    【解决方案2】:

    您是对的,这很尴尬,但这只是因为您试图在值转换器中为集合添加一些管理,而不是在集合本身上。我认为,如果您的收藏更清楚其项目具有 IsSelected 属性,这将有所帮助:

    public CustomCollection : Collection<CustomObject> {
        CustomObject _current;
        public CustomObject CurrentSelection {
            get { return _current; }
            set {
                if (_current == value)
                    return;
    
                if (_current != null)
                    _current.IsSelected = false;
    
                if (value != null)
                    value.IsSelected = true;
    
                _current = value;
            }
        }
    }
    

    只需添加一点额外内容,以确保 _current 至少是集合中的第一个元素。

    <ComboBox ItemsSource="{Binding}" SelectedItem="{Binding CurrentSelection}">
    

    现在您应该不再需要转换器了。然而,有一些考虑缺失。您可能想改用ObservableCollection&lt;T&gt; 并在CurrentSelection 更改时引发PropertyChanged 事件,这样如果有任何其他内容绑定到该属性或在代码中发生更改,所有绑定都会相应更新。

    编辑:包装模型

    一种包装集合的简单方法,而不是像上面那样制作自定义集合:

    public class CollectionWrapper : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged = (o,e)=>{};
        // never have to check for null
    
        public CollectionWrapper(Collection<CustomObject> collection) {
            Items = collection;
        }
    
        // unlikely to change, so let's prevent it for now
        public Collection<CustomObject> Items {
            get;
            private set;
        }
    
        CustomObject _current;
        public CustomObject CurrentSelection {
            get { return _current; }
            set {
                if (_current == value)
                    return;
    
                if (_current != null)
                    _current.IsSelected = false;
    
                if (value != null)
                    value.IsSelected = true;
    
                _current = value;
                PropertyChanged(this, new PropertyChangedEventArgs("CurrentSelection"));
            }
        }
    }
    

    然后这个对象变成了你的数据上下文,ComboBox 绑定变成了这个:

    <ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding CurrentSelection}">
    

    【讨论】:

    • 是的,更改数据模型可能是最好的解决方案,但在当前情况下并不容易。也许我会为这个特定绑定的集合创建一个多余的“包装器”类。
    猜你喜欢
    • 2013-03-03
    • 2020-01-15
    • 2018-11-24
    • 1970-01-01
    • 2020-05-15
    • 2013-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多