WPF ComboBox无法在属性更改事件上更新

时间:2019-01-31 14:56:55

标签: c# wpf

我在WPF应用程序中有一个自定义组合框,并且在首次启动后更新我的商品来源时,组合框没有更新。 itemsSource是一个自定义的observableDictionary。我已经使用我的observableDictionary在属性上实现了INotifyPropertyChanged,但不会更新。我已经搜索了每个WPF属性更改事件,但这些事件在堆栈溢出方面不起作用,我正在寻求帮助。

自定义组合框代码:

<controls:MultiSelectComboBox Width="100" Height="30" Padding="0 10 0 0" Grid.Row="0" Grid.Column="1"
    ItemsSource="{Binding Mode=TwoWay,             
                  UpdateSourceTrigger=PropertyChanged,                                                    
                  ValidatesOnDataErrors=True, 
                  Path=DataContext.OptionTeamMembersDictionary, 
                  BindsDirectlyToSource=True,                                                    
                  RelativeSource={RelativeSource AncestorType={x:Type UserControl},Mode=FindAncestor}}"
    SelectedItems="{Binding SelectedOptionTeamMembersDictionary, Mode=TwoWay}"
    x:Name="TeamMemberDisplay" 
    ToolTip="{Binding Path=Text, RelativeSource={RelativeSource Self}}"/>

属性和私有变量:

private ObservableDictionary<string, object> _optionTeamMembersDictionary;
private ObservableDictionary<string, object> _selectedOptionTeamMembersDictionary;


public ObservableDictionary<string, object> OptionTeamMembersDictionary
{
    get
    {
        return _optionTeamMembersDictionary;
    }
    set
    {
        _optionTeamMembersDictionary = value;
        OnPropertyChanged("OptionTeamMembersDictionary");
    }
}

public ObservableDictionary<string, object> SelectedOptionTeamMembersDictionary
{
    get
    {
        return _selectedOptionTeamMembersDictionary;
    }
    set
    {
        _selectedOptionTeamMembersDictionary = value;
        OnPropertyChanged("SelectedOptionTeamMembersDictionary");
    }
}

我使用一个按钮触发数据库拉动,该操作将每一行引导到一个对象中,然后在optionTeamMemberDictionary选项返回多于一行数据时填充它。

在将数据加载到我的构造函数中但在启动后加载其组合框时,上述所有方法均无法在集合中显示新数据。

编辑: 用于自定义ComboBox的代码: https://www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF是此URL的来源。进行了一些编辑以实现ObserableDirctionary而不是普通词典

public partial class MultiSelectComboBox : UserControl
{
    private ObservableCollection<Node> _nodeList;
    public MultiSelectComboBox()
    {
        InitializeComponent();
        _nodeList = new ObservableCollection<Node>();
    }

    #region Dependency Properties

    public static readonly DependencyProperty ItemsSourceProperty =
         DependencyProperty.Register("ItemsSource", typeof(ObservableDictionary<string, object>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
    new PropertyChangedCallback(MultiSelectComboBox.OnItemsSourceChanged)));

    public static readonly DependencyProperty SelectedItemsProperty =
     DependencyProperty.Register("SelectedItems", typeof(ObservableDictionary<string, object>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
 new PropertyChangedCallback(MultiSelectComboBox.OnSelectedItemsChanged)));

    public static readonly DependencyProperty TextProperty =
       DependencyProperty.Register("Text", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));

    public static readonly DependencyProperty DefaultTextProperty =
        DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));

    public ObservableDictionary<string, object> ItemsSource
    {
        get { return (ObservableDictionary<string, object>)GetValue(ItemsSourceProperty); }
        set
        {
            SetValue(ItemsSourceProperty, value);
        }
    }

    public ObservableDictionary<string, object> SelectedItems
    {
        get { return (ObservableDictionary<string, object>)GetValue(SelectedItemsProperty); }
        set
        {
            SetValue(SelectedItemsProperty, value);
        }
    }

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public string DefaultText
    {
        get { return (string)GetValue(DefaultTextProperty); }
        set { SetValue(DefaultTextProperty, value); }
    }
    #endregion

    #region Events
    private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MultiSelectComboBox control = (MultiSelectComboBox)d;
        control.DisplayInControl();
    }

    private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MultiSelectComboBox control = (MultiSelectComboBox)d;
        control.SelectNodes();
        control.SetText();
    }

    private void CheckBox_Click(object sender, RoutedEventArgs e)
    {
        CheckBox clickedBox = (CheckBox)sender;

        if (clickedBox.Content == "All")
        {
            if (clickedBox.IsChecked.Value)
            {
                foreach (Node node in _nodeList)
                {
                    node.IsSelected = true;
                }
            }
            else
            {
                foreach (Node node in _nodeList)
                {
                    node.IsSelected = false;
                }
            }
        }
        else
        {
            int _selectedCount = 0;
            foreach (Node s in _nodeList)
            {
                if (s.IsSelected && s.Title != "All")
                    _selectedCount++;
            }
            if (_selectedCount == _nodeList.Count - 1)
                _nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = true;
            else
                _nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = false;
        }
        SetSelectedItems();
        SetText();
    }
    #endregion

    #region Methods
    private void SelectNodes()
    {
        foreach (KeyValuePair<string, object> keyValue in SelectedItems)
        {
            Node node = _nodeList.FirstOrDefault(i => i.Title == keyValue.Key);
            if (node != null)
                node.IsSelected = true;
        }
    }

    private void SetSelectedItems()
    {
        if (SelectedItems == null)
            SelectedItems = new ObservableDictionary<string, object>();
        SelectedItems.Clear();
        foreach (Node node in _nodeList)
        {
            if (node.IsSelected && node.Title != "All")
            {
                if (this.ItemsSource.Count > 0)
                    SelectedItems.Add(node.Title, this.ItemsSource[node.Title]);
            }
        }
    }

    private void DisplayInControl()
    {
        _nodeList.Clear();
        if (this.ItemsSource.Count > 0)
            _nodeList.Add(new Node("All"));
        foreach (KeyValuePair<string, object> keyValue in this.ItemsSource)
        {
            Node node = new Node(keyValue.Key);
            _nodeList.Add(node);
        }
        MultiSelectCombo.ItemsSource = _nodeList;
    }

    private void SetText()
    {
        if (this.SelectedItems != null)
        {
            StringBuilder displayText = new StringBuilder();
            foreach (Node s in _nodeList)
            {
                if (s.IsSelected == true && s.Title == "All")
                {
                    displayText = new StringBuilder();
                    displayText.Append("All");
                    break;
                }
                else if (s.IsSelected == true && s.Title != "All")
                {
                    displayText.Append(s.Title);
                    displayText.Append(',');
                }
            }
            this.Text = displayText.ToString().TrimEnd(new char[] { ',' });
        }
        // set DefaultText if nothing else selected
        if (string.IsNullOrEmpty(this.Text))
        {
            this.Text = this.DefaultText;
        }
    }


    #endregion
}

public class Node : INotifyPropertyChanged
{

    private string _title;
    private bool _isSelected;
    #region ctor
    public Node(string title)
    {
        Title = title;
    }
    #endregion

    #region Properties
    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            _title = value;
            NotifyPropertyChanged("Title");
        }
    }
    public bool IsSelected
    {
        get
        {
            return _isSelected;
        }
        set
        {
            _isSelected = value;
            NotifyPropertyChanged("IsSelected");
        }
    }
    #endregion

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

1 个答案:

答案 0 :(得分:0)

经过大量故障排除后,我能够找到答案。实例化控件后,onItemsSourceChanged没有触发,因此在应用程序首次启动后就从未进行过更新。我将MultiFunctionComboBox上的OnItemsSourceChanged函数编辑为以下内容,因此它将在发生更改的事件上触发,并且现在可以按预期运行。

private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MultiSelectComboBox control = (MultiSelectComboBox)d;

            var action = new NotifyCollectionChangedEventHandler(
                (o, args) =>
                {
                    MultiSelectComboBox c = (MultiSelectComboBox)d;

                    c?.DisplayInControl();
                });

            if (e.OldValue != null)
            {
                var sourceCollection = (ObservableDictionary<string, object>)e.OldValue;
                sourceCollection.CollectionChanged -= action;
            }

            if (e.NewValue != null)
            {
                var sourceCollection = (ObservableDictionary<string, object>)e.NewValue;
                sourceCollection.CollectionChanged += action;
            }

            control.DisplayInControl();
        }