tags:

views:

132

answers:

1

Hello,

I have an wpf mvvm application. I try to write checkbox list control.
I can bind the checkbox list elements.
Added to this issue, I want to get sum of the selected checkbox list elements values.
I added DependencyProperty and bind it to view model property.
But, they dont fire each other.

CheckBoxList User Control Xaml

<ListBox x:Name="ItemsControl" ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Text}" IsChecked="{Binding IsSelected, Mode=TwoWay}" 
                      Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

CheckBoxList Code Behind

public partial class CheckBoxList : UserControl
{
    public CheckBoxList()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty SelectedCheckBoxItemsValueProperty =
        DependencyProperty.Register("SelectedCheckBoxItemsValue", typeof(int), typeof(CheckBoxList),
            new FrameworkPropertyMetadata(
                0,
                new FrameworkPropertyMetadata(0, OnSelectedItemsChanged));

    public int SelectedCheckBoxItemsValue
    {
        get { return (int)GetValue(SelectedCheckBoxItemsValueProperty); }
        set { SetValue(SelectedCheckBoxItemsValueProperty, value); }
    }

    private static int GetSelectedCheckBoxItemsValue(DependencyObject obj)
    {
        return (int)obj.GetValue(SelectedCheckBoxItemsValueProperty);
    }

    private static void OnSelectedItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        CheckBoxList checkboxList = obj as CheckBoxList;
        ObservableCollection<ISelectableItem> items = checkboxList.DataContext as ObservableCollection<ISelectableItem>;

        foreach (var item in items)
        {
            item.IsSelected = (GetSelectedCheckBoxItemsValue(obj) & item.Value) != 0;
        }
    }

    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        CheckBoxList checkboxList = sender as CheckBoxList;
        ObservableCollection<ISelectableItem> coll = ItemsControl.DataContext as ObservableCollection<ISelectableItem>;
        if (coll == null) return;

        int count = 0;
        foreach (var item in coll)
        {
            if (item.IsSelected)
            {
                count += item.Value;
            }
        }

        SelectedCheckBoxItemsValue = count;
    }
}

SelectableItem Class

public interface ISelectableItem : INotifyPropertyChanged
{
    bool IsSelected { get; set; }
    string Text { get; set; }
    int Value { get; set; }
    string GroupName { get; set; }
}

public class SelectableItem : ISelectableItem
{ ....

ViewModel Property

    public int SelectedCheckBoxEnumItemsValue
    {
        get
        {
            return _selectedCheckBoxEnumItemsValue;
        }
        set
        {
            _selectedCheckBoxEnumItemsValue = value;
            NotifyOfPropertyChange("SelectedCheckBoxEnumItemsValue");
        }
    }

At Binder Class

        string selectedItemPropertyName = "Selected" + viewModelProperty.Name + "Value";
        var property = viewModelProperties.FirstOrDefault(p => p.Name.Contains(selectedItemPropertyName));

        if (property != null)
        {
            var selectedItemOrValueBinding = new Binding(property.Name)
            {
                Mode = property.CanWrite ? BindingMode.TwoWay : BindingMode.OneWay,
                ValidatesOnDataErrors = Attribute.GetCustomAttributes(property, typeof(ValidationAttribute), true).Any()
            };

            BindingOperations.SetBinding(control, CheckBoxList.SelectedCheckBoxItemsValueProperty, selectedItemOrValueBinding);
        }
A: 

Below code solves your problem..

Please Note the segrgation of view models.

<StackPanel>
            <TextBlock Text="{Binding Count}"></TextBlock>
            <ListBox x:Name="ItemsControl" ItemsSource="{Binding CheckList}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <CheckBox Name="item" Content="{Binding Text}" IsChecked="{Binding IsSelected, Mode=TwoWay}"  Command="{Binding CheckboxCheckedCommand}" CommandParameter="{Binding IsChecked, ElementName=item}"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

        </StackPanel>    




     public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                DataContext = new MasterViewModel();
            }
         }




public class MasterViewModel : INotifyPropertyChanged
{
    private List<CheckBoxItem> checkList;
    private int count;

    public int Count
    {
        get
        {
            return count;
        }
        set
        {
            count = value;
            OnPropertyChanged("Count");
        }
    }
    public List<CheckBoxItem> CheckList
    {
        get
        {
            return checkList;
        }
        set
        {
            checkList = value;
            OnPropertyChanged("CheckList");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    public MasterViewModel()
    {
        checkList = new List<CheckBoxItem>();
        for (int i = 0; i < 5; i++)
        {
            CheckBoxItem item = new CheckBoxItem();
            item.Text = i.ToString();
            item.IsSelected = false;
            item.CheckboxCheckedCommand = new RelayCommand(new Action<object>(ExecuteCheckCommand));
            checkList.Add(item);
        }

    }
    private void ExecuteCheckCommand(object parameter)
    {
        if (parameter.GetType() == typeof(bool))
        {
            bool value = bool.Parse(parameter.ToString());
            int val = count;
            if (value)
            {     
                val++;                                   
            }
            else
            {
                val--;
            }
            Count = val;
        }
    }

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

public class CheckBoxItem : INotifyPropertyChanged
{
    private bool isSelected;
    private string text;

    public string Text
    {
        get 
        {
            return text;
        }
        set
        {
            text = value;
            OnPropertyChanged("Text");
        }
    }
    public bool IsSelected
    {
        get
        {
            return isSelected;
        }
        set
        {
            isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }

    public ICommand CheckboxCheckedCommand
    {
        get;
        set;
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

public class RelayCommand : ICommand
{
    private Action<object> executeCommand;

    public RelayCommand(Action<object> executeCommand)
    {
        this.executeCommand = executeCommand;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        executeCommand(parameter);
    }
}
Rakesh Gunijan
In my code, can you suggest where the problem is?
pirimoglu
If above solution solves your problem, then please mark it as answer.Yes, first try to define responsibility for your control. Try to refer articles on MVVM, they will improve your understanding on WPF. Referring to your code I found numerous issues, starting with need of creating control.
Rakesh Gunijan