user1247076
user1247076

Reputation: 13

Combobox with Checkboxes

I am trying to make a combobox that shows check boxes, and selecting each checkbox will update the text of the combobox to display everything that has been checked. For some strange reason it works only on the first item in the checkbox and it has completely baffled me as to why. I have a dummy project that is pretty small that demonstrates it...

public partial class MainWindow : Window
{
    public ObservableCollection<DataObject> Collection { get; set; }
    #region Private Methods
    public MainWindow()
    {
        InitializeComponent();
        Collection = new ObservableCollection<DataObject>();
        Collection.Add(new DataObject { Name = "item1" });
        Collection.Add(new DataObject { Name = "item2" });
        Collection.Add(new DataObject { Name = "item3" });
        Collection.Add(new DataObject { Name = "item4" });
        Collection.Add(new DataObject { Name = "item5" });
        this.DataContext = Collection;
    }
    #endregion

    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        CheckBox chk = sender as CheckBox;
        DataObject data = chk.DataContext as DataObject;
        if ((bool)chk.IsChecked)
            data.CboItems.Add(data.Name);
        else if (data.CboItems.Contains(data.Name))
            data.CboItems.Remove(data.Name);

    }

}

public class DataObject : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;
    public string Name { get; set; }
    private string cbotext;
    public string CBOText {
        get
        {
            return cbotext;
        }
        set
        {
            cbotext = value;
            FirePropertyChanged("CBOText");
        }
    }
    public ObservableCollection<string> CboItems { get; set; }

    private void FirePropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

    public DataObject()
    {
        CboItems = new ObservableCollection<string>();
        CboItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(CboItems_CollectionChanged);
    }

    void CboItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        string text = string.Empty;
        foreach (string item in CboItems)
        {
            if (text == string.Empty)
                text = item;
            else
                text += ", " + item;
        }
        CBOText = text;
    }
}

and the Xaml...

    <ComboBox Text="{Binding CBOText}" Width="150" Height="30" ItemsSource="{Binding}" x:Name="cbo" HorizontalContentAlignment="Stretch" IsEditable="True" Margin="12,12,342,270">
        <ComboBox.ItemTemplate>
            <DataTemplate>     
                <CheckBox Content="{Binding Name}" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

I can see the event CBOText string getting set correctly and firing PropertyChanged, but the combobox does not reflect it unless it's the first item. Quite weird, any ideas?

Upvotes: 1

Views: 3647

Answers (1)

Eric Dahlvang
Eric Dahlvang

Reputation: 8292

Your bindings are setup incorrectly. Try something like this:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public ObservableCollection<DataObject> Collection { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;

    #region Private Methods
    public MainWindow()
    {

        InitializeComponent();
        Collection = new ObservableCollection<DataObject>();
        Collection.Add(new DataObject { Name = "item1" });
        Collection.Add(new DataObject { Name = "item2" });
        Collection.Add(new DataObject { Name = "item3" });
        Collection.Add(new DataObject { Name = "item4" });
        Collection.Add(new DataObject { Name = "item5" });
        this.DataContext = this;
    }
    #endregion

    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        CheckBox chk = sender as CheckBox;
        DataObject data = chk.DataContext as DataObject;
        string combinedText = string.Empty;
        foreach (var item in this.Collection)
        {
            if (item.IsChecked.HasValue && item.IsChecked.Value)
            {
                if (combinedText == string.Empty)
                    combinedText = item.Name;
                else
                    combinedText += ", " + item.Name;
            }
        }
        CboText = combinedText;
    }

    private string _cboCombinedText = "" ;
    public string CboText 
    {
        get 
        { 
            return this._cboCombinedText; }
        set
        {
            this._cboCombinedText = value;
            PropertyChanged(this, new PropertyChangedEventArgs("CboText"));
        }
    }

    public class DataObject 
    {
        private bool? _isChecked = false;
        public string Name { get; set; }
        public bool? IsChecked { get { return _isChecked; } set { _isChecked = value; } }
    }
}

And xaml:

        <ComboBox Text="{Binding CboText}" Width="150" Height="30" ItemsSource="{Binding Path=Collection}" x:Name="cbo" HorizontalContentAlignment="Stretch" IsEditable="True" Margin="12,12,342,270">
        <ComboBox.ItemTemplate >
            <DataTemplate >
                <CheckBox Content="{Binding Name}" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" IsChecked="{Binding IsChecked}" />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

Upvotes: 1

Related Questions