views:

98

answers:

0

Hi Experts,

I have a combo box inside a user control and i am trying to update an observable collection with the change event of this combo box. This combo box has a list view inside it. I have added a working example of this scenario so you can copy paste it in your VS IDE. The user control in this example is just a part of the original user control. I have removed the code which are not required.

--Customer.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace TestMVVM
{
    class Customer : INotifyPropertyChanged
    {

        public int ID { get; set; }
        public int NumberOfContracts { get; set; }

        private string firstName;
        private string lastName;

        public string FirstName
        {
            get { return firstName; }
            set
            {
                if (firstName != value)
                {
                    firstName = value;
                    RaisePropertyChanged("FirstName");

                }
            }
        }

        public string LastName
        {
            get { return lastName; }
            set
            {
                if (lastName != value)
                {
                    lastName = value;
                    RaisePropertyChanged("LastName");
                }
            }
        }

        #region PropertChanged Block
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
        #endregion
    }
}

--CustomerHeaderViewModel class

class CustomerHeaderViewModel
{
    public ObservableCollection<Customer> Customers { get; set; }

    public void LoadCustomers()
    {
        ObservableCollection<Customer> customers = new ObservableCollection<Customer>();

        //this is where you would actually call your service
        customers.Add(new Customer { ID = 1, FirstName = "Jim", LastName = "Smith", NumberOfContracts = 23 });

        Customers = customers;
    }
}

-- UCComboBox.xaml User Control

<UserControl x:Class="TestMVVM.UCComboBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="25" Width="200">
    <Grid>
        <ComboBox Height="23" HorizontalAlignment="Left" Margin="0,0,0,0" Name="cmbComboBoxControl" 
        VerticalAlignment="Top" Width="195" 
        IsEditable="True"/>
    </Grid>
</UserControl>

-- UCComboBox.xaml.cs CodeBehind

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.Data;
using System.ComponentModel;
using System.Windows.Controls.Primitives;

namespace TestMVVM
{
    /// <summary>
    /// Interaction logic for UCComboBox.xaml
    /// </summary>
    public partial class UCComboBox : UserControl
    {
        public static readonly DependencyProperty ComboValueProperty =
            DependencyProperty.Register("ComboValue", typeof(string), typeof(UCComboBox));

        ListView _lstvMyView;
        private string _valueColumn = "Id";
        private string _displayColumn = "Display";
        private DataTable _dataSource = null;

        public UCComboBox()
        {
            InitializeComponent();
        }

        private string _comboValue;

        public string ComboValue
        {
            get 
            {
                return (string)GetValue(ComboValueProperty); 
            }
            set 
            {
                DataRow dr = null;

                _comboValue = value;
                SetValue(ComboValueProperty, value);

                if (_comboValue != "")
                {
                    if (_dataSource != null && _dataSource.Rows.Count > 0)
                    {
                        for (int i = 0; i < _dataSource.Rows.Count; i++)
                        {
                            if (_dataSource.Rows[i][_valueColumn].ToString() == value)
                            {
                                dr = _dataSource.Rows[i];
                                break;
                            }
                        }


                        if (dr == null)
                        {
                            cmbComboBoxControl.Text = "";
                        }
                        else
                        {
                            cmbComboBoxControl.Text = dr[_displayColumn].ToString();
                        }
                    }
                }
            }
        }

        public void LoadFromResultSet(DataTable dt)
        {
            _dataSource = dt;
            CreateListView(dt);

            cmbComboBoxControl.Items.Clear();
            cmbComboBoxControl.Items.Add(_lstvMyView);
        }

        /// <summary>
        /// Creates the listview and binds data to it.
        /// </summary>
        /// <param name="dt"></param>
        private void CreateListView(DataTable dt)
        {
            DataTable ListViewdt = dt;

            _lstvMyView = new ListView();

            Binding binding = new Binding();
            binding.Source = ListViewdt.DefaultView;

            _lstvMyView.SetBinding(ListView.ItemsSourceProperty, binding);

            GridView grid = new GridView();

            GridViewColumn gridcol = new GridViewColumn();
            gridcol.Width = cmbComboBoxControl.Width;
            gridcol.DisplayMemberBinding = new Binding(_displayColumn);
            grid.Columns.Add(gridcol);

            Style style = new Style(typeof(GridViewColumnHeader));
            style.Setters.Add(new Setter { Property = GridViewColumnHeader.VisibilityProperty, Value = Visibility.Collapsed});
            grid.ColumnHeaderContainerStyle = style;

            _lstvMyView.View = grid;

            _lstvMyView.SelectionChanged += new SelectionChangedEventHandler(lstvMyView_SelectionChanged);
        }

        private void lstvMyView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_lstvMyView.ItemsSource != null)
            {
                DataRowView drv = (_lstvMyView.SelectedValue as DataRowView);
                if (drv != null)
                {
                    ComboValue = drv.Row[_valueColumn].ToString();
                }
                cmbComboBoxControl.IsDropDownOpen = false;
            }
        }
    }
}

-- Window2.xaml

<Window x:Class="TestMVVM.Window2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestMVVM"
    Title="Window2" Height="300" Width="300" Loaded="Window_Loaded">
    <Grid>
        <local:UCComboBox x:Name="cmbUC" />
        <Button Height="23" HorizontalAlignment="Left" Margin="39,0,0,82" 
                Name="btnUpdate" VerticalAlignment="Bottom" Width="75" Click="btnUpdate_Click">Update</Button>
        <Button Height="23" Margin="120,0,83,82" Name="btnChange" VerticalAlignment="Bottom" Click="btnChange_Click">Change</Button>
    </Grid>
</Window>

-- Window2.xaml.cs

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.Shapes;
using System.Data;
using System.Collections.ObjectModel;

namespace TestMVVM
{
    /// <summary>
    /// Interaction logic for Window2.xaml
    /// </summary>
    public partial class Window2 : Window
    {
        CustomerHeaderViewModel customerHeaderViewModel = null;
        public Window2()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            CreateDataTableParent();
            cmbUC.LoadFromResultSet(dtableparent);

            customerHeaderViewModel = new CustomerHeaderViewModel();
            customerHeaderViewModel.LoadCustomers();

            cmbUC.ComboValue = customerHeaderViewModel.Customers[0].ID.ToString();
        }

        DataTable dtableparent;
        private void CreateDataTableParent()
        {
            dtableparent = new DataTable("Rock");
            DataRow drow;

            //set columns names
            dtableparent.Columns.Add("Id", typeof(System.String));
            dtableparent.Columns.Add("Display", typeof(System.String));

            //Add Rows
            drow = dtableparent.NewRow();
            drow["Id"] = "1";
            drow["Display"] = "aaaa";
            dtableparent.Rows.Add(drow);

            drow = dtableparent.NewRow();
            drow["Id"] = "2";
            drow["Display"] = "bbbb";
            dtableparent.Rows.Add(drow);

            drow = dtableparent.NewRow();
            drow["Id"] = "3";
            drow["Display"] = "cccc";
            dtableparent.Rows.Add(drow);

            drow = dtableparent.NewRow();
            drow["Id"] = "4";
            drow["Display"] = "dddd";
            dtableparent.Rows.Add(drow);
        }

        private void btnChange_Click(object sender, RoutedEventArgs e)
        {
            cmbUC.ComboValue = "2";
        }

        private void btnUpdate_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(customerHeaderViewModel.Customers[0].ID.ToString());
        }
    }
}

My question here is when i click on Change button the combo value changes but when i click on update button the value still remains the same. The same happens when i change the combo value through the UI. How can i make the observable collection update itself on change of the ComboValue property of the user control?

Please help! Thanks in advance!

Regards,

Samar