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