简体   繁体   English

WPF ComboBox不会在propertychanged事件上更新

[英]WPF ComboBox Not updating on propertychanged event

I have a custom combobox in my WPF application and the combo box is not updating when my item source is updated after initial launch. 我的WPF应用程序中有一个自定义组合框,并且在首次启动后更新我的商品来源时,组合框没有更新。 The itemsSource is a custom observableDictionary. itemsSource是一个自定义的observableDictionary。 I've implemented INotifyPropertyChanged on my properties with my observableDictionary but it won't update. 我已经使用我的observableDictionary在属性上实现了INotifyPropertyChanged,但不会更新。 I've searched through every WPF propertychanged event not working on stack overflow and i'm looking for some assistance. 我已经搜索了每个WPF属性更改事件,但这些事件在堆栈溢出时不起作用,我正在寻求帮助。

Custom Combobox Code: 自定义组合框代码:

<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}}"/>

Properties and private variables: 属性和私有变量:

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

I use a button to trigger a database pull which leads each row into an object and then populates the optionTeamMemberDictionary when it returns more then one row of data. 我使用一个按钮来触发数据库提取,该提取将每一行引导到一个对象中,然后在optionTeamMemberDictionary选项返回多于一行数据时填充它。

All of the above works when the data is loaded in my constructor but when its loaded after launch my comboboxes do not show the new data in the collection. 当将数据加载到构造函数中时,上述所有方法均有效,但是在启动后加载数据时,组合框不会在集合中显示新数据。

EDIT: Code for the Custom ComboBox being used: https://www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF is the URL this came from. 编辑:正在使用的自定义组合框的代码: https : //www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF是来自此的URL。 Some edits were made to implement an obserableDirctionary instead of normal dictionary 进行了一些编辑以实现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));
    }
}

After much troubleshooting i was able to figure out an answer for this. 经过大量的故障排除后,我能够找到答案。 onItemsSourceChanged was not firing after the control was instantiated so it never got updates made after initial launch of the application. 实例化控件后,onItemsSourceChanged没有触发,因此在应用程序首次启动后就从未进行过更新。 I edited the OnItemsSourceChanged Function on the MultiFunctionComboBox to the below so it would fire on a changed event and it is working as expected now. 我将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();
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM