【问题标题】:Combobox SelectedItem Becomes Null组合框 SelectedItem 变为空
【发布时间】:2016-09-06 05:25:11
【问题描述】:

我正在尝试制作一个在对象之间切换的 ComboBox。一般的要点是一个对象有一个出现在 ComboBox 中的 Key 和一个理论上可以是任何东西的 Data 组件。 Data 组件很复杂,而 Key 只是一个字符串。对于下面的示例,Data 只是一个 Uri,实际上 Data 的类型并不重要。

基本意图是将ComboBox的SelectedItem绑定到Model,以便通过其他交互修改SelectedItem的Data。

代码设置为将几个项目添加到 ComboBox,然后选择 SelectedItem 作为第一个元素。这工作得很好。然后,当我单击该按钮时,SelectedItem 被分配为 null 我抛出异常的地方。

为什么 SelectedItem 被赋值为 null?

这是完整的工作代码;我的目标是 .NET 4.0,但我猜这无关紧要。 Xaml 如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace Sandbox
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public Model Model { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            Model = new Model();

            this.Model.Items.Add(
                new ObservableKeyValuePair<string, Uri>()
                {
                    Key = "Apple",
                    Value = new Uri("http://apple.com")
                });

            this.Model.Items.Add(
                new ObservableKeyValuePair<string, Uri>()
                {
                    Key = "Banana",
                    Value = new Uri("http://Banana.net")
                });

            this.Model.SelectedItem = this.Model.Items.First();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Model.SelectedItem.Value = new Uri("http://cranberry.com");
        }
    }

    public class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
    {
        public TrulyObservableCollection()
        {
            CollectionChanged += FullObservableCollectionCollectionChanged;
        }

        public TrulyObservableCollection(IEnumerable<T> pItems)
            : this()
        {
            foreach (var item in pItems)
            {
                this.Add(item);
            }
        }

        private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (Object item in e.NewItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
                }
            }
            if (e.OldItems != null)
            {
                foreach (Object item in e.OldItems)
                {
                    ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
                }
            }
        }

        private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
            OnCollectionChanged(args);
        }
    }

    public class ObservableKeyValuePair<TKey, TValue> :
        INotifyPropertyChanged,
        IEquatable<ObservableKeyValuePair<TKey, TValue>>
    {
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }

        public override bool Equals(object rhs)
        {
            var obj = rhs as ObservableKeyValuePair<TKey, TValue>;

            if (obj != null)
            {
                return this.Key.Equals(obj.Key);
            }

            return false;
        }

        public bool Equals(ObservableKeyValuePair<TKey, TValue> other)
        {
            return this.Key.Equals(other.Key);
        }

        public override int GetHashCode()
        {
            return this.Key.GetHashCode();
        }

        protected TKey _Key;
        public TKey Key
        {
            get
            {
                return _Key;
            }
            set
            {
                if (value is INotifyPropertyChanged)
                {
                    (value as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(KeyChanged);
                }

                _Key = value;

                OnPropertyChanged("Key");
            }
        }
        void KeyChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged("Key");
        }

        protected TValue _Value;
        public TValue Value
        {
            get
            {
                return _Value;
            }
            set
            {
                if (value is INotifyPropertyChanged)
                {
                    (value as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(ValueChanged);
                }

                _Value = value;

                OnPropertyChanged("Value");
            }
        }
        void ValueChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged("Value");
        }
    }

    public class Model : INotifyPropertyChanged
    {
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        public Model()
        {
            Items = new TrulyObservableCollection<ObservableKeyValuePair<string, Uri>>();
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }

        public TrulyObservableCollection<ObservableKeyValuePair<string, Uri>> Items { get; set; }
        public ObservableKeyValuePair<string, Uri> _SelectedItem = null;
        public ObservableKeyValuePair<string, Uri> SelectedItem
        {
            get
            {
                return Items.FirstOrDefault(x => _SelectedItem != null && x.Key == _SelectedItem.Key);
            }
            set
            {
                if (value == null)
                {
                    throw new Exception("This is the problem");
                }

                if (_SelectedItem != value)
                {
                    _SelectedItem = value;
                    OnPropertyChanged("SelectedItem");
                }
            }
        }
    }
}

Xaml:

<Window x:Class="Sandbox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Button Click="Button_Click" Content="Clsick Me"/>
        <ComboBox IsEditable="False" ItemsSource="{Binding Model.Items}" SelectedItem="{Binding Model.SelectedItem, Mode=TwoWay}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Key}">
                    </TextBlock>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>

试图解释为什么“价值”为空,我完全不知所措。

【问题讨论】:

  • 点击按钮时你想做什么?您想将SelectedItem 更改为不同的还是只更改当前SelectedItemvalue 属性
  • @Gopichandar 我想更改 SelectedItem 的属性;在示例中,属性是值。我不会更改 Equals 使用的任何属性。

标签: c# wpf xaml combobox


【解决方案1】:

根本问题在于Selector.OnItemsChanged 的实现。在方法接近尾声时,当前的SelectedItem 为空。

我通过派生一个新的ComboBox 类来解决这个问题,该类覆盖OnItemsChanged,保存当前SelectedItem,调用base.OnItemsChanged,然后重置SelectedItem。如果不需要从 valid=>null=>valid 的 SelectedItem 转换,这可能需要将“InhibitEvents”标志传播到模型中。

【讨论】:

    【解决方案2】:

    该值变为空,因为您试图分配一个不在集合中的选定项值

    【讨论】:

    • SelectedItem 已经在集合中。我正在尝试修改现有 SelectedItem 的属性。 Equals() 逻辑中也不使用值。
    猜你喜欢
    • 2021-10-15
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多