WPF displaying object properties from Observable Collection MVVM - wpf

I am trying to display the properties from an object which is contained in an observable list but it is just not working.
I was hoping someone could point me in the right direction.
Here is my XAMl
<Window x:Name="MainViewWindow" x:Class="WpfApplication1.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:WpfApplication1.ViewModel"
Title="MainView" Height="413.514" Width="607.095">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Label Content="Text:" HorizontalAlignment="Left" Margin="55,135,0,0" VerticalAlignment="Top"/>
<Label Content="{Binding Name}" HorizontalAlignment="Left" Margin="98,135,0,0" VerticalAlignment="Top"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="61,108,0,0" VerticalAlignment="Top" Width="75" Command="{Binding UpdateNameCommand}"/>
<Label Content="ActivateButton" HorizontalAlignment="Left" Margin="52,82,0,0" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin="173,87,0,0" VerticalAlignment="Top" IsChecked="{Binding ButtonActive}" />
<Label Content="CustomerName" HorizontalAlignment="Left" Margin="55,166,0,0" VerticalAlignment="Top"/>
<StackPanel HorizontalAlignment="Left" Height="100" Margin="173,166,0,0" VerticalAlignment="Top" Width="100"/>
<ItemsControl x:Name="lstPeople" Background="AliceBlue" Width="130" Margin="273,29,196,35" ItemsSource="{Binding CustomerList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
My CustomerList is a property located in the MainViewModel:
ObservableCollection<Customer> _CustomerList;
ObservableCollection<Customer> CustomerList
{
get { return _CustomerList; }
set
{
if (_CustomerList != value)
{
_CustomerList = value;
PropertyChanged(this, new PropertyChangedEventArgs("CustomerList"));
}
}
}
My Customer class only contains one property: Name
public class Customer : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
if (_Name != value)
{
_Name = value;
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
I have created an instance of the CustomerList in the MainViewModel constructor but i cannot see any of my customers showing up in the application:
public MainViewModel()
{
ButtonActive = true;
CustomerList = new ObservableCollection<Customer>() { new Customer() { Name = "NewCust33" } };
CustomerList.Add(new Customer() { Name = "NewCust" });
}

It looks like the property you're binding to is private?
You can only bind to public properties.
public ObservableCollection<Customer> CustomerList

Related

Assign combobox value in wpf

Please let me know how to assign value to combobox with following code, as assign the Display text
`<ComboBox x:Name="ComboBox" HorizontalAlignment="Left" Margin="256,41,0,-6"
VerticalAlignment="Top" Width="108" Height="26" FontSize="13" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>`
You can simply use DisplayMemberPath property to set the name of the column of your DataTable which will be displayed.
Code behind:
ComboBox.ItemsSource = dt.AsDataView();
XAML:
<ComboBox x:Name="ComboBox" DisplayMemberPath="Name" HorizontalAlignment="Left" Margin="256,41,0,-6"
VerticalAlignment="Top" Width="108" Height="26" FontSize="13">
</ComboBox>
You have to create a list of strings called Name in your viewModel that implements INotifyPropertyChanged
XAML:
<ComboBox x:Name="ComboBox" ItemsSource="{Binding myListofItems}" HorizontalAlignment="Left" Margin="256,41,0,-6" VerticalAlignment="Top" Width="108" Height="26" FontSize="13" />
C#:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private List<string> _myListOfItems = new List<string> ();
public List<string> myListOfItems
{
get { return (_myListOfItems); }
set
{
_myListOfItems = value;
OnPropertyChanged ("myListOfItems");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) {
handler (this, new PropertyChangedEventArgs (propertyName));
}
}
public MainWindow()
{
InitializeComponent ();
this.DataContext = this;
// Start Populating your List here
// Example:
for (int i = 0; i < 10; i++) {
myListOfItems.Add (i.ToString ());
}
}
}
<ComboBox x:Name="cmbSubLocation"
DisplayMemberPath="SubLocationName" SelectedValuePath="Id"
VerticalAlignment="Top" Width="108" Height="26" FontSize="13" >
</ComboBox>

WPF : Passing Custom data to between Custom Control and parent

I am total newbie to WPF. I am creating my custom user control which will display the employee data structure which is as follows I have implemented INotifyPropertyChanged also:
Here's code snippet
public class Employee : INotifyPropertyChanged
{
private int id;
private string name;
private double salary;
private EmployeeDesignation designation;
public int ID
{
get
{
return id;
}
set
{
id = value;
OnPropertyChanged(new PropertyChangedEventArgs("ID"));
//PropertyChanged(ID, new PropertyChangedEventArgs("ID"));
}
}
...
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
}
}
And user control code is as follows :
<UserControl x:Class="Assignment5.EmployeeUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://scenter code herehemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}"
d:DesignHeight="196" d:DesignWidth="300">
<Grid Height="182">
<Label Content="Name" Height="28" HorizontalAlignment="Left" Margin="26,57,0,0" Name="label1" VerticalAlignment="Top" Width="76" />
<Label Content="Salary" Height="28" HorizontalAlignment="Left" Margin="26,91,0,0" Name="label2" VerticalAlignment="Top" />
<Label Content="ID" Height="28" HorizontalAlignment="Left" Margin="26,23,0,0" Name="label3" VerticalAlignment="Top" />
<Label Content="Designation" Height="28" HorizontalAlignment="Left" Margin="26,125,0,0" Name="label4" VerticalAlignment="Top" />
<TextBox Text="{Binding ElementName=Employee, Path=ID}" Height="23" HorizontalAlignment="Left" Margin="134,28,0,0" Name="IdTextBox" VerticalAlignment="Top" Width="120" />
<TextBox Text="{Binding ElementName=Employee, Path=Name}" Height="23" HorizontalAlignment="Left" Margin="134,59,0,0" Name="NameTextBox" VerticalAlignment="Top" Width="120" />
<TextBox Text="{Binding ElementName=Employee, Path=Salary}" Height="23" HorizontalAlignment="Left" Margin="134,91,0,0" Name="SalaryTextBox" VerticalAlignment="Top" Width="120" LostFocus="SalaryTextBoxLostFocus" />
<TextBox Text="{Binding ElementName=Employee, Path=designation}" Height="23" HorizontalAlignment="Left" Margin="134,125,0,0" Name="DesignationTextBox" VerticalAlignment="Top" Width="120" />
</Grid>
</UserControl>
Here's code behind file
namespace Assignment5
{
public partial class EmployeeUserControl : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty EmpDependancyProperty =
DependencyProperty.Register("Employee", typeof(Employee), typeof(EmployeeUserControl)
, new PropertyMetadata(
new PropertyChangedCallback(
EmployeeUserControl.EmployeeDataChanged)));
public Employee Employee
{
get
{
return (Employee)GetValue(EmpDependancyProperty);
}
set
{
SetValue(EmpDependancyProperty, value);
}
}
public EmployeeUserControl()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private void SalaryTextBoxLostFocus(object sender, RoutedEventArgs e)
{
MessageBox.Show(Employee.Name);
}
private static void EmployeeDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
EmployeeUserControl userControl = d as EmployeeUserControl;
userControl.OnPropertyChanged("Employee");
}
}
}
Here's my parent control...
<Window x:Class="Assignment5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:Assignment5"
DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}">
<Grid>
<my:EmployeeUserControl Employee="{Binding Path=emp, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True}" HorizontalAlignment="Left" Margin="130,56,0,0" x:Name="employeeUserControl1" VerticalAlignment="Top" Width="285" />
</Grid>
</Window>
and a code behind :
namespace Assignment5
{
public partial class MainWindow : Window
{
public static readonly DependencyProperty EmpDependancyProperty =
DependencyProperty.Register("Employee", typeof(Employee), typeof(EmployeeUserControl)
, new PropertyMetadata(
new PropertyChangedCallback(
EmployeeUserControl.EmployeeDataChanged)));
public Employee Employee
{
get
{
return (Employee)GetValue(EmpDependancyProperty);
}
set
{
SetValue(EmpDependancyProperty, value);
}
}
public MainWindow()
{
emp = new Employee(203,"AAA",23232);
InitializeComponent();
}
}
}
When I run this code. I came to know that Employee object in parent control is getting initialized but in the user control it is not getting initialized. What I am doing wrong here?
Two issues
In your UserControl change the Bindings to
<TextBox Text="{Binding Path=Employee.ID}" Height="23" HorizontalAlignment="Left" Margin="134,28,0,0" Name="IdTextBox" VerticalAlignment="Top" Width="120" />
<TextBox Text="{Binding Employee.Name}" Height="23" HorizontalAlignment="Left" Margin="134,59,0,0" Name="NameTextBox" VerticalAlignment="Top" Width="120" />
<TextBox Text="{Binding Employee.Salary}" Height="23" HorizontalAlignment="Left" Margin="134,91,0,0" Name="SalaryTextBox" VerticalAlignment="Top" Width="120" LostFocus="SalaryTextBoxLostFocus" />
<TextBox Text="{Binding Employee.designation}" Height="23" HorizontalAlignment="Left" Margin="134,125,0,0" Name="DesignationTextBox" VerticalAlignment="Top" Width="120" />
In your Window:
<my:EmployeeUserControl Employee="{Binding Employee, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True}" HorizontalAlignment="Left" Margin="130,56,0,0" x:Name="employeeUserControl1" VerticalAlignment="Top" Width="285" />
In your constructor emp = new Employee(203,"AAA",23232); does not make any sense. Instead do this.Employee = new Employee(203,"AAA",23232);

TwoWay data binding between various controls

I'm very new to WPF, (I started yesterday) and I'm very confused about data binding. I have a View Model for a Window, which contains a widget called Foo which has its own View Model.
The widget Foo binds its Visibility TwoWay (via a BooleanToVisibilityConverter) to a bool field Visible on its FooViewModel. FooViewModel implements INotifyPropertyChanged and fires a PropertyChanged event whenever Visible is set.
In the Xaml for the Window, it creates a Foo whenever a button is clicked. The Window's view model has another boolean field which is bound TwoWay to the Visibility of its instance of a Foo View. The view model of the WIndow implements INotifyPropertyChanged and fires PropertyChanged events whenever the boolean field is modified.
What I expect this to do is whenever the window's boolean property changes, the visibility of the Foo instance will be set. When this happens I expect the View Model of Foo to be updated, since Foo's visibility binding is two way. When the Foo View Model changes its boolean field I expect the View to change its visibility. Further, I expect the Window view model to be notified that its instance of Foo is no longer visible, and hence the View model of the Window will update its own boolean field. Is this a fundamental misunderstanding?
I post the (obfuscated) code below if it helps shed light on this misunderstanding. Thanks.
Window Xaml
<Window x:Class="XXX.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:XXX.ViewModel"
xmlns:v="clr-namespace:XXX"
Title="MainWindow" Height="350" Width="525" WindowStartupLocation="CenterOwner" WindowState="Maximized">
<Window.Resources>
<vm:AppViewModel x:Key="AppViewModel"/>
<vm:TwoWayVisibilityConverter x:Key="BoolToVisibility" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource AppViewModel}}">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Connection" Command="{Binding Authenticate}"/>
<MenuItem Header="_About" Command="{Binding ShowAbout}"/>
<MenuItem Header="_Logout" Command="{Binding Logout}"/>
<MenuItem Header="_Configuration" Command="{Binding Configuration}"/>
<MenuItem Header="_Info" Command="{Binding ShowInfo}"/>
</Menu>
<StackPanel>
</StackPanel>
</DockPanel>
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
Padding="10"
BorderThickness="0">
<TextBlock Text="XXX"/>
</Border>
<Grid x:Name="Overlay" Panel.ZIndex="1000" DataContext="{Binding Source={StaticResource AppViewModel}}">
<Border HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Visibility="{Binding Path=Modal, Converter={StaticResource BoolToVisibility}, Mode=OneWay}"
Background="DarkGray"
Opacity=".7" />
<v:Configuration HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Path=ConfigurationVisible, Converter={StaticResource BoolToVisibility}, Mode=TwoWay}"/>
<v:Connect HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Path=AuthenticateVisible, Converter={StaticResource BoolToVisibility}, Mode=TwoWay}"/>
</Grid>
</Grid>
Window View Model
class AppViewModel : INotifyPropertyChanged
{
[Import(typeof (IEventBus))] private IEventBus _bus;
public AppViewModel()
{
Authenticate = new ForwardCommand(obj => ShowAuthenticationView(), obj => !AuthenticateVisible);
Configuration = new ForwardCommand(obj => ShowConfigurationView(), obj => !ConfigurationVisible);
}
public bool Modal
{
get
{
return AuthenticateVisible || ConfigurationVisible;
}
}
public ICommand Authenticate { get; set; }
public bool AuthenticateVisible { get; set; }
public ICommand ShowInfo { get; set; }
public ICommand ShowAbout { get; set; }
public ICommand Logout { get; set; }
public ICommand Configuration { get; set; }
public bool ConfigurationVisible { get; set; }
private void ShowAuthenticationView()
{
AuthenticateVisible = !AuthenticateVisible;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("AuthenticateVisible"));
PropertyChanged(this, new PropertyChangedEventArgs("Modal"));
}
}
private void ShowConfigurationView()
{
ConfigurationVisible = !ConfigurationVisible;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("ConfigurationVisible"));
PropertyChanged(this, new PropertyChangedEventArgs("Modal"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
UserControl Xaml
<UserControl x:Class="XXX.Connect"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:XXX.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<vm:ConnectViewModel x:Key="ViewModel"/>
<vm:TwoWayVisibilityConverter x:Key="BoolToVisibility" />
</UserControl.Resources>
<Grid Width="280"
Height="173"
DataContext="{Binding Source={StaticResource ViewModel}}"
Visibility="{Binding Path=Visible, Converter={StaticResource BoolToVisibility}, Mode=TwoWay}"
Background="White">
<Label Content="URL" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,12,0,0" Name="url" VerticalAlignment="Top" Width="169" Text="{Binding Path=Url, Mode=OneWayToSource}" TabIndex="0" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,70,0,0" Name="username" VerticalAlignment="Top" Width="171" Text="{Binding Path=Username, Mode=OneWayToSource}" TabIndex="2" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,41,0,0" Name="password" VerticalAlignment="Top" Width="169" Text="{Binding Path=Password, Mode=OneWayToSource}" TabIndex="1" />
<Label Content="Username" Height="28" HorizontalAlignment="Left" Margin="12,39,0,0" Name="label3" VerticalAlignment="Top" />
<Label Content="Password" Height="28" HorizontalAlignment="Left" Margin="12,68,0,0" Name="label2" VerticalAlignment="Top" />
<DockPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="13">
<Button Content="OK" Height="23" HorizontalAlignment="Left" Margin="5" Name="ok" VerticalAlignment="Top" Width="75" Command="{Binding ConnectCommand}" TabIndex="3" />
<Button Content="Cancel" Height="23" HorizontalAlignment="Left" Margin="5" Name="cancel" VerticalAlignment="Top" Width="75" Command="{Binding CloseCommand}" TabIndex="4" />
</DockPanel>
</Grid>
</UserControl>
UserControl View Model
internal class ConnectViewModel : INotifyPropertyChanged
{
[Import(typeof (IEventBus))] private IEventBus _bus;
public ConnectViewModel()
{
ConnectCommand = new ForwardCommand(obj => Fire(),
obj =>
Visible && !String.IsNullOrEmpty(Url) && !String.IsNullOrEmpty(Url) &&
!String.IsNullOrEmpty(Url));
CloseCommand = new ForwardCommand(obj => Hide(), obj => Visible);
}
public ICommand ConnectCommand { get; set; }
public ICommand CloseCommand { get; set; }
public string Url { get; set; }
public string Username { get; set; }
public string Password { get; set; }
private bool _visible;
public bool Visible
{
get { return _visible; }
set { _visible = value; }
}
private void Fire()
{
_bus.Publish<SessionCreatedEvent, SessionEventHandler>(new SessionCreatedEvent(Url, Username, Password));
Hide();
}
private void Hide()
{
Visible = false;
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Binding always works on properties. So while you Raise Visible in your Hide method, you don't raise it in the actual property. But the property is what the binding engine will set. If you bind this to another dependency property it won't get notified about it.
Btw. whats a TwoWayVisibilityConverter? BooleanToVisibilityConverter is perfectly capable of handling two way bindings.
tl;dr to make two way binding work properly (and in fact even one way binding) you need to implement INotifyPropertyChanged properly which means, if the setter is called raise the property.
public bool Visible
{
get { return _visible; }
set
{
_visible = value;
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
}

ListBox binding with ViewModel in WPF

I am new to the WPF and trying to build a sample application using the MVVM framework. My application has a xaml file which has some textboxes for inputing customer info, combo box for display of states and a save button. All the databinding is done through ViewModel(CustomerViewMode) which has a reference to the Model(Customer), containing the required fields and their
Getter, setters. The viewModel has a CustomerList property.
On clicking the save button, I want to display the FirstName and LastName properties of Customer in a ListBox. This is where the problem is. I debugged the code,
(Click event of button in the code behind), I can see that the CustomerList has the first Customer object with all its details, but its not getting displayed in the listbox.
My code is:
Customer(Model);
enter code here
namespace SampleMVVM.Models
{
class Customer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private String _firstName;
private String _lastName;
private Address _customerAddress;
public String FirstName
{
get { return _firstName; }
set
{
if (value != _firstName)
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
}
public String LastName
{
get { return _lastName; }
set
{
if (value != _lastName)
{
_lastName = value;
RaisePropertyChanged("LastName");
}
}
}
public Address CustomerAddress
{
get { return _customerAddress; }
set
{
if (value != _customerAddress)
{
_customerAddress = value;
RaisePropertyChanged("CustomerAddress");
}
}
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Address(Model)
namespace SampleMVVM.Models
{
class Address : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _addressLine1;
private string _addressLine2;
private string _city;
//private string _selectedState;
private string _postalCode;
private string _country;
public String AddressLine1
{
get { return _addressLine1; }
set
{
if (value != _addressLine1)
{
_addressLine1 = value;
RaisePropertyChanged(AddressLine1);
}
}
}
public String AddressLine2
{
get { return _addressLine2; }
set
{
if (value != _addressLine2)
{
_addressLine2 = value;
RaisePropertyChanged(AddressLine2);
}
}
}
public String City
{
get { return _city; }
set
{
if (value != _city)
{
_city = value;
RaisePropertyChanged(City);
}
}
}
public String PostalCode
{
get { return _postalCode; }
set
{
if (value != _postalCode)
{
_postalCode = value;
RaisePropertyChanged(PostalCode);
}
}
}
public String Country
{
get { return _country; }
set
{
if (value != _country)
{
_country = value;
RaisePropertyChanged(Country);
}
}
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
CustomerViewModel:
namespace SampleMVVM.ViewModels
{
class CustomerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Customer _customer;
RelayCommand _saveCommand;
private List<String> _stateList = new List<string>();
private string _selectedState;
private ObservableCollection<Customer> _customerList = new ObservableCollection<Customer>();
//public CustomerViewModel(ObservableCollection<Customer> customers)
//{
// _customers = new ListCollectionView(customers);
//}
public Customer CustomerModel
{
get { return _customer; }
set
{
if (value != _customer)
{
_customer = value;
RaisePropertyChanged("CustomerModel");
}
}
}
public List<String> StateList
{
get
{
return _stateList;
}
set { _stateList = value; }
}
public ObservableCollection<Customer> CustomerList
{
get
{
return _customerList;
}
set
{
if (value != _customerList)
{
_customerList = value;
RaisePropertyChanged("CustomerList");
}
}
}
public CustomerViewModel()
{
CustomerModel = new Customer
{
FirstName = "Fred",
LastName = "Anders",
CustomerAddress = new Address
{
AddressLine1 = "Northeastern University",
AddressLine2 = "360, Huntington Avenue",
City = "Boston",
PostalCode = "02115",
Country = "US",
}
};
StateList = new List<String>
{
"Alaska", "Arizona", "California", "Connecticut", "Massachusetts", "New Jersey", "Pennsylvania", "Texas"
};
SelectedState = StateList.FirstOrDefault();
}
public String SelectedState
{
get { return _selectedState; }
set
{
if (value != _selectedState)
{
_selectedState = value;
RaisePropertyChanged(SelectedState);
}
}
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
CustomerInfo.xaml(view)
<UserControl x:Class="SampleMVVM.Views.CustomerInfo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ViewModels="clr-namespace:SampleMVVM.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<ViewModels:CustomerViewModel />
</UserControl.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!--Starting label-->
<TextBlock FontSize="18" FontFamily="Comic Sans MS" FontWeight="ExtraBlack"
Foreground="Navy"
Grid.Row="0" HorizontalAlignment="Center">
<TextBlock.Text>
Customer Information:
</TextBlock.Text>
</TextBlock>
<TextBlock Text="First name: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="1" Width="80px" Height="50px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.FirstName}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="1" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0" Name="fname"/>
<TextBlock Text="Last Name: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="2" Width="80px" Height="50px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.LastName}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="2" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0" Name="lname"/>
<TextBlock Text="Address: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="3" Width="80px" Height="50px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.AddressLine1}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="3" Grid.Column="1" Width="160px" Height="20px" Margin="20,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.AddressLine2}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="4" Grid.Column="1" Width="160px" Height="30px" Margin="20,5,0,0"/>
<TextBlock Text="City: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="5" Width="80px" Height="20px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.City}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="5" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"/>
<TextBlock Text="State: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="6" Width="80px" Height="20px" Margin="40,5,0,0"/>
<ComboBox Grid.RowSpan="2" HorizontalAlignment="Left" Name="listOfSates"
VerticalAlignment="Top"
Grid.Row="6" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"
ItemsSource="{Binding Path=StateList}"
SelectedItem="{Binding Path=SelectedState}"
SelectionChanged="ComboBox_SelectionChanged"
>
</ComboBox>
<TextBlock Text="PostalCode: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="7" Width="80px" Height="20px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.PostalCode}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="7" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"/>
<TextBlock Text="Country: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="8" Width="80px" Height="20px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.Country}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="8" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"/>
<Button Content="Save" Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="9" Width="50px" Height="20px" Name="savebtn" Margin="40,5,0,0"
Click="savebtn_Click"/>
<ListBox Name="cList" ItemsSource="{Binding Path=CustomerList}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="1" Grid.Column="2" Grid.RowSpan="2" Width="200px" Height="300px" Margin="200,5,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding CustomerModel.FirstName}"
FontWeight="Bold" Foreground="Navy"/>
<TextBlock Text=", " />
<TextBlock Text="{Binding CustomerModel.LastName}"
FontWeight="Bold" Foreground="Navy"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
CustomerInfo(Code behind class)
namespace SampleMVVM.Views
{
/// <summary>
/// Interaction logic for CustomerInfo.xaml
/// </summary>
public partial class CustomerInfo : UserControl
{
public CustomerInfo()
{
InitializeComponent();
//checkvalue();
}
private void savebtn_Click(object sender, RoutedEventArgs e)
{
////Customer c = new Customer();
////c.FirstName = fname.Text;
////c.LastName = lname.Text;
//CustomerViewModel cvm = new CustomerViewModel();
//cvm.CustomerModel.FirstName = fname.Text;
//cvm.CustomerModel.LastName = lname.Text;
//List<CustomerViewModel> customerList = new List<CustomerViewModel>();
//customerList.Add(cvm);
var viewModel = DataContext as CustomerViewModel;
if (viewModel != null)
{
//viewModel.ShowCustomerInfo();
String strfname = viewModel.CustomerModel.FirstName;
String strname = viewModel.CustomerModel.LastName;
viewModel.CustomerList.Add(viewModel.CustomerModel);
String str1 = viewModel.CustomerList.FirstOrDefault().FirstName;
int i = viewModel.CustomerList.Count();
//cList.ItemsSource = viewModel.CustomerList;
}
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CustomerViewModel cvm = new CustomerViewModel();
cvm.SelectedState = listOfSates.SelectedItem.ToString();
}
}
}
I just cant understand where am I going wrong...Someone please help
And for the correct binding in ListBox.ItemTemplate:
<TextBlock Text="{Binding FirstName}"
FontWeight="Bold" Foreground="Navy"/>
<TextBlock Text="{Binding LastName}"
FontWeight="Bold" Foreground="Navy"/>
The DataContext of ListBoxItem is a Customer already.
You only create a new instance of a CustomerModel object once in your code (in the Customer View Model constructor). So you are constantly updating the same customer object rather than creating a new one.
At the end of your click handler you should do a
viewModel.CustomerModel = new Customer();
HOWEVER
Rather than having a click handler you should have an ICommand in your view model for adding a new customer. Then you should bind to command of your button to the ICommand in your view model.
you were binding the CustomerLIst.FirstName which is not walid because innterconent will check for property name customerlist in side the listbox itemssource. and as its not their then it will raise a silent error but wo't show into GUI, what you need to do is just provide the propertyname like firstname and lastname that will work.
well besides your binding in listbox every thing else is ok. just replace you listbox binding as like below.
<TextBlock Grid.Row="0"
Grid.Column="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="List of Customers" />
<ListBox Name="cList"
Grid.Row="1"
Grid.RowSpan="8"
Grid.Column="2"
ItemsSource="{Binding CustomerList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock FontWeight="Bold"
Foreground="Black"
Text="{Binding FirstName}" />
<TextBlock Text=", " />
<TextBlock FontWeight="Bold"
Foreground="Black"
Text="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="10"
Grid.Column="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding CustomerList.Count,
StringFormat='Total Customers, ={0}'}" />
better to take command insteed of events.
Your problem is in this line of code:
RaisePropertyChanged("CustomerList");
It doesn't work for collection add/remove events. Take a look at ObservableCollection and Item PropertyChanged.
Keep in mind that in MVVM, you should not have much code (if any) in code behind. Consider using commands.

Observablecollection<T> in Listbox is not updating

I have a Silverlight Listbox bound to Observablecollection which shows up fine (first time) but when I try to update it through the code behind, the change does not reflect in UI. I have used MVVM pattern . Pl have a look and at view and viewmodel.
<UserControl x:Class="GridOperations.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GridOperations.ViewModel"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="700">
<UserControl.DataContext>
<local:ShowUserListViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
<local:ShowUserListViewModel x:Key="viewModelKey"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<ListBox VerticalAlignment="Top" Margin="0,20,0,0" x:Name="lstBox" ItemsSource="{Binding UserList}" Width="700" Height="150" Background="AliceBlue">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Margin="30,0,0,0" Text="{Binding UserId}" HorizontalAlignment="Left"/>
<TextBlock Margin="30,0,0,0" Text="{Binding Path=UserName, Mode=TwoWay}" Grid.Column="1" HorizontalAlignment="Left"/>
<Button Margin="30,0,0,0" Grid.Column="2" Content="Edit" Height="20" HorizontalAlignment="Left" Command="{Binding Source={StaticResource viewModelKey}, Path=UpdateUserCommand}" />
<Button Margin="10,0,0,0" Grid.Column="3" Content="Del" Height="20" HorizontalAlignment="Left" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
public class ShowUserListViewModel : INotifyPropertyChanged
{
public ShowUserListViewModel()
{
mUserList = new ObservableCollection<User>();
mUserList.Add(new User() { UserId = Guid.NewGuid().ToString(), UserName = "testuser1", IsAdmin = true });
mUserList.Add(new User() { UserId = Guid.NewGuid().ToString(), UserName = "testuser2", IsAdmin = true });
this.UpdateUserCommand = new DelegateCommand(this.UpdateUser);
}
public ICommand UpdateUserCommand { get; private set; }
private ObservableCollection<User> mUserList;
public ObservableCollection<User> UserList
{
get
{
return mUserList;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void UpdateUser()
{
this.UserList.Add(new User() { UserId = Guid.NewGuid().ToString(), UserName = "test", IsAdmin = false });
}
}
Firstly, you should avoid putting a collection property writable. IE, replace this code :
private ObservableCollection<User> mUsers = new ObservableCollection<User>();
public ObservableCollection<User> Users
{
get
{
return mUsers;
}
set
{
mUsers = value;
RaisePropertyChangedEvent("Users");
}
}
by this code :
private ObservableCollection<User> mUsers = new ObservableCollection<User>();
public ObservableCollection<User> Users
{
get
{
return mUsers;
}
}
Then, when you add an item to the collection, you don't have to tell the collection has changed (the collection property hasn't changed in itself), but it's the responsibility of the collection itself (via INotifyCollectionChanged) :
So, the "onclick" method can be simply like this:
private void OnClick(User userInstanceToEdit)
{
this.Users.Add(new User() { UserId = Guid.NewGuid().ToString(), UserName = "test", IsAdmin = false });
}
Finally, I would replace the ListBox.ItemsSource declaration with this one, as two ways is not required :
<ListBox x:Name="lstBox" ItemsSource="{Binding Users}"
Got a hint from this post Stackoverflow
Basically I need to use Datacontext with Listbox control (even after setting the Datacontext at UserControl level). The only line that required change is:
<ListBox x:Name="lstBox" ItemsSource="{Binding Users}" DataContext="{StaticResource viewModelKey}" Width="750" Background="AliceBlue">

Resources