WPF : Passing Custom data to between Custom Control and parent - wpf

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);

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 displaying object properties from Observable Collection MVVM

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

how to get textbox value from View to ViewModel in Silverlight MVVM?

Currently now i'm using silverlight5 with MVVM. in SL5 i need to do the following.
I have 3 textbox and 1 button control and i datagrid in the xaml(Design page).
here is the Design View(Xaml):
<UserControl.DataContext>
<VC:EmployeeListViewModel />
</UserControl.DataContext>
<Grid x:Name="LayoutRoot">
<my:DataGrid x:Name="McDataGrid" ItemsSource="{Binding Employees,UpdateSourceTrigger=PropertyChanged}" Margin="130,151,0,0" Height="137" VerticalAlignment="Top" RowBackground="#AA5D9324" AutoGenerateColumns="True" HorizontalAlignment="Left" Width="193">
</my:DataGrid>
<Button Content="Show Message" Width="100" Height="25" Margin="256,75,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<si:CallDataMethod Method="AddEmployeeCommand"/>
<si:ShowMessageBox Caption="Thank you"
Message="Thanks for trying the Example"
MessageBoxButton="OK"/>
<si:SetProperty TargetName="LayoutRoot"
PropertyName="Background" Value="PaleGoldenrod"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<TextBlock FontWeight="Bold" Height="26" HorizontalAlignment="Left" Margin="47,12,0,0" Name="textBlock1" Text="First Name:" VerticalAlignment="Top" Width="77" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Employee.Fname}" />
<TextBlock FontWeight="Bold" Height="25" HorizontalAlignment="Left" Margin="35,44,0,0" Name="textBlock2" Text="Second Name:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,44,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
<TextBlock FontWeight="Bold" Height="23" HorizontalAlignment="Left" Margin="45,75,0,0" Name="textBlock3" Text="Department:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,75,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" />
<!-- Add reference to Microsoft.Expression.Interactions.dll, System.Windows.Interactivity.dll -->
<!-- Use mvvmxmlns snippet to add i and ei namespace prefixes -->
</ComboBox>
<TextBlock Height="23" HorizontalAlignment="Left" Margin="64,122,0,0" Name="textBlock4" Text="Choose:" VerticalAlignment="Top" FontWeight="Bold" />
</Grid>
</UserControl>
in the same project i create one folder named 'ViewModel':
in the same folder i add one class file named: EmployeeListViewModel.cs
my question is this. how to pass the textbox value to the viewmodel[EmployeeListViewModel] and insert the it to the Datagrid.
EmployeeListViewModel.cs:
public class EmployeeListViewModel:INotifyPropertyChanged
{
public ObservableCollection<Employee> Employees { get; private set; }
public EmployeeListViewModel()
{
Employees = Silverlight_MVVM.DataHelper.EmployeeDataHelper.EmployeeData ();
}
private Employee _SelectedEmployee;
public Employee SelectedEmployee
{
get
{
return _SelectedEmployee;
}
set
{
_SelectedEmployee = value;
RaisePropertyChanged("SelectedEmployee");
}
}
private Employee _Names;
public Employee Names
{
get
{
return _Names;
}
set
{
_Names = value;
RaisePropertyChanged("Names");
}
}
public void HandleShowMessage()
{
// MessageBox.Show("Hello " + Names + ",Welcome to EventTrigger for MVVM.");
}
public RelayCommand _AddEmployeeCommand;
/// <summary>
/// Returns a command that show the customer.
/// </summary>
public ICommand AddEmployeeCommand
{
get
{
if (_AddEmployeeCommand == null)
{
_AddEmployeeCommand = new RelayCommand(
param => this.AddEmployee(),
param => this.CanAddEmployee
);
}
return _AddEmployeeCommand;
}
}
public bool CanAddEmployee
{
get
{
return true;
}
}
public void AddEmployee()
{
//Employee newEmployee = new Employee("New1);
Employee newEmployee = new Employee() **{};**
--> **Here i have to pass the value.. How is it possible..?**
Employees.Add(newEmployee);
SelectedEmployee = newEmployee;
}
#region INotifyPropertyChanged
// [field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Not 100% sure how you are going about this?
Usually I would have the grid bound to the selected employee as you have, then have the values of the text boxes bound to the properties on the selectedemployee. As you change row, these would then update to reflect the values of the currently selected row in the grid.
So then you add a new blank employee and it would have blank values until they were entered in the text box. Of course, you'd need to build in some validation to ensure you don't get loads of blabnk rows added.
If I'm correct in my understanding of how you are wanting to do it, then as it stands the values in the text boxes are not related to the selected row, but are used just to add a new employee with those values? to achieve this I would suggest having the Textbox bind to a string value on the Viewmodel. Currently you have them bound to something that doesn't appear to actually exist. Instead, I'd bind them to their own properties on the view model thus:
private string _employeeFirstName;
public string EmployeeFirstName
{
get
{
return _employeeFirstName;
}
set
{
_employeeFirstName= value;
RaisePropertyChanged("EmployeeFirstName");
}
}
and then in the xaml bind to that property - with Mode=TwoWay so that the viewmodel also recieves any updates
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=EmployeeFirstName, Mode=TwoWay}" />
then when creating your new employee:
public void AddEmployee()
{
Employee newEmployee = new Employee() {FName = this.EmployeeFirstName};
Employees.Add(newEmployee);
SelectedEmployee = newEmployee;
}
You have to use TwoWay binding mode. For example, Text="{Binding Path=Employee.Fname,Mode=TwoWay}". You can read more about Binding.Mode on MSDN.
i create three property named Fname,Sname,Dept respectly in View Model..
private string _fname;
public string Fname
{
get
{
return _fname;
}
set
{
_fname = value;
RaisePropertyChanged("Fname");
}
}
And the function is as follows..
public void AddEmployee()
{
Employee newEmployee = new Employee() {Fname=this.Fname;Sname=this.Sname;Dept=this.Dept};
Employees.Add(newEmployee);
SelectedEmployee = newEmployee;
}
It Works Well..
Design Code is :
<TextBlock FontWeight="Bold" Height="26" HorizontalAlignment="Left" Margin="47,12,0,0" Name="textBlock1" Text="First Name:" VerticalAlignment="Top" Width="77" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Fname,Mode=TwoWay}" />
<TextBlock FontWeight="Bold" Height="25" HorizontalAlignment="Left" Margin="35,44,0,0" Name="textBlock2" Text="Second Name:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,44,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text="{Binding Path=Sname,Mode=TwoWay}"/>
<TextBlock FontWeight="Bold" Height="23" HorizontalAlignment="Left" Margin="45,75,0,0" Name="textBlock3" Text="Department:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,75,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" Text="{Binding Path=Dept,Mode=TwoWay}"/>
<Button Content="Show Message" Width="100" Height="25" Margin="256,75,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<si:CallDataMethod Method="AddEmployee"/>
<si:ShowMessageBox Caption="Thank you"
Message="Thanks for trying the Example"
MessageBoxButton="OK"/>
<si:SetProperty TargetName="LayoutRoot"
PropertyName="Background" Value="PaleGoldenrod"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Hope it will useful to us..

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.

Adding/removing User Controls on Canvas in WPF

I have created two WPF user controls having multiple textboxes, comboboxes and buttons. In the main wpf window, I have created a Canvas and a listbox with two listitems in it. My requirement is, if select the first listbox item, the first user control should get added to canvas. If I select the second listbox item, the previously added user control should get hide, and second one should get added/showed. Can anyone provide an expample for this code?
Below is code I have writtent.I have created two user controls.
UserControl1.xaml
<UserControl x:Class="UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="210" Height="210" x:Name="UCntl1">
<Grid>
<StackPanel>
<GroupBox Header="Text Boxes">
<StackPanel Orientation="Horizontal">
<StackPanel>
<Label Margin="4" Height="21">TextBox1</Label>
<Label Margin="4" Height="21">TextBox2</Label>
<Label Margin="4" Height="21">TextBox3</Label>
</StackPanel>
<StackPanel>
<TextBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4">0.1</TextBox>
<TextBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4">0.2</TextBox>
<TextBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4">0.3</TextBox>
</StackPanel>
</StackPanel>
</GroupBox>
<GroupBox Header="Conbo Boxes">
<StackPanel Orientation="Horizontal">
<StackPanel>
<Label Margin="4" Height="21">ComboBox1</Label>
<Label Margin="4" Height="21">ComboBox2</Label>
<Label Margin="4" Height="21">ComboBox3</Label>
</StackPanel>
<StackPanel>
<ComboBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4">
<ComboBoxItem>Item AAA</ComboBoxItem>
</ComboBox>
<ComboBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4">
<ComboBoxItem>Item BBB</ComboBoxItem>
</ComboBox>
<ComboBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4">
<ComboBoxItem>Item CCC</ComboBoxItem>
</ComboBox>
</StackPanel>
</StackPanel>
</GroupBox>
</StackPanel>
</Grid>
</UserControl>
UserControl2.xaml
<UserControl x:Class="UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="210" Height="210" x:Name="UCntl2">
<Grid>
<StackPanel>
<GroupBox Header="Conbo Boxes">
<StackPanel Orientation="Horizontal">
<StackPanel>
<Label Margin="4" Height="21">ComboBox1</Label>
<Label Margin="4" Height="21">ComboBox2</Label>
<Label Margin="4" Height="21">ComboBox3</Label>
</StackPanel>
<StackPanel>
<ComboBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4"></ComboBox>
<ComboBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4"></ComboBox>
<ComboBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4"></ComboBox>
</StackPanel>
</StackPanel>
</GroupBox>
<GroupBox Header="Text Boxes">
<StackPanel Orientation="Horizontal">
<StackPanel>
<Label Margin="4" Height="21">TextBox1</Label>
<Label Margin="4" Height="21">TextBox2</Label>
<Label Margin="4" Height="21">TextBox3</Label>
</StackPanel>
<StackPanel>
<TextBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4"></TextBox>
<TextBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4"></TextBox>
<TextBox Width="100" Height="21" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="4"></TextBox>
</StackPanel>
</StackPanel>
</GroupBox>
</StackPanel>
</Grid>
Window1.xaml
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="Auto" Width="Auto">
<Grid>
<StackPanel Orientation="Horizontal">
<Grid Margin="0,0,0,0" Width="Auto" Height="Auto" VerticalAlignment="Top">
<ListBox Margin="0,0,0,0" HorizontalAlignment="Left" Width="Auto" Height="Auto" VerticalAlignment="Top" BorderBrush="White">
<ListBoxItem Name="LstItem1" Selected="LstItem1_Selected">User Control 1</ListBoxItem>
<ListBoxItem Name="LstItem2" Selected="LstItem2_Selected">User Control 2</ListBoxItem>
</ListBox>
</Grid>
<Grid Width="10" Background="LightGray"></Grid>
<Grid Margin="0,0,0,0">
<Canvas Name="Canvas1" Width="210" Height="210" VerticalAlignment="Top">
</Canvas>
</Grid>
</StackPanel>
</Grid>
Widow1.xaml.vb
Class Window1
Private Sub LstItem1_Selected(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Canvas1.Children.Clear()
Canvas1.Children.Add(New UserControl1)
End Sub
Private Sub LstItem2_Selected(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Canvas1.Children.Clear()
Canvas1.Children.Add(New UserControl2)
End Sub
End Class
Problem
I have added the user control after removing the previous controls in the canvas. Because of this the selected values in the list boxes in UserControls are getting cleared while re-adding the control to the canvas. Is there any method to hide the usercontrols on the canvas, instead of removing the controls from canvas.
This should get you started. It's not exactly how I'd do it in a real project, but close enough. I wish there was an easy way to attach projects to answers on this site.
The end result looks like this:
App.xaml:
<Application x:Class="SO9735486.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:SO9735486.ViewModels"
xmlns:v="clr-namespace:SO9735486.Views"
StartupUri="MainWindow.xaml">
<Application.Resources>
<DataTemplate DataType="{x:Type vm:MainViewModel}">
<v:MainView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:FirstContentViewModel}">
<v:FirstContentView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SecondContentViewModel}">
<v:SecondContentView/>
</DataTemplate>
</Application.Resources>
</Application>
MainWindow.xaml:
<Window x:Class="SO9735486.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
</Window>
MainWindow.xaml.cs:
namespace SO9735486
{
using System.Windows;
using SO9735486.ViewModels;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Content = new MainViewModel();
}
}
}
ViewModel.cs:
namespace SO9735486.ViewModels
{
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Threading;
// http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html
public abstract class ViewModel : INotifyPropertyChanged
{
private readonly Dispatcher _dispatcher;
protected ViewModel()
{
if (Application.Current != null)
{
_dispatcher = Application.Current.Dispatcher;
}
else
{
//this is useful for unit tests where there is no application running
_dispatcher = Dispatcher.CurrentDispatcher;
}
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
protected Dispatcher Dispatcher
{
get { return _dispatcher; }
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
}
ContentViewModel.cs:
namespace SO9735486.ViewModels
{
public abstract class ContentViewModel : ViewModel
{
private readonly string displayName;
protected ContentViewModel(string displayName)
{
this.displayName = displayName;
}
public string DisplayName
{
get { return this.displayName; }
}
}
}
FirstContentViewModel.cs:
namespace SO9735486.ViewModels
{
public sealed class FirstContentViewModel : ContentViewModel
{
private string name;
public FirstContentViewModel()
: base("First")
{
}
public string Name
{
get { return this.name; }
set
{
if (this.name != value)
{
this.name = value;
this.OnPropertyChanged("Name");
}
}
}
}
}
SecondContentViewModel.cs:
namespace SO9735486.ViewModels
{
public sealed class SecondContentViewModel : ContentViewModel
{
public SecondContentViewModel()
: base("Second")
{
}
}
}
MainViewModel.cs:
namespace SO9735486.ViewModels
{
using System.Collections.Generic;
using System.Linq;
public sealed class MainViewModel : ViewModel
{
private readonly ICollection<ContentViewModel> contentViewModels;
private ContentViewModel selectedContentViewModel;
public MainViewModel()
{
this.contentViewModels = new List<ContentViewModel>
{
new FirstContentViewModel(),
new SecondContentViewModel()
};
this.selectedContentViewModel = this.contentViewModels.First();
}
public ICollection<ContentViewModel> ContentViewModels
{
get { return this.contentViewModels; }
}
public ContentViewModel SelectedContentViewModel
{
get { return this.selectedContentViewModel; }
set
{
if (this.selectedContentViewModel != value)
{
this.selectedContentViewModel = value;
this.OnPropertyChanged("SelectedContentViewModel");
}
}
}
}
}
FirstContentView.xaml:
<UserControl x:Class="SO9735486.Views.FirstContentView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Label>First Content View</Label>
<TextBox Text="{Binding Name}"/>
</StackPanel>
</UserControl>
SecondContentView.xaml:
<UserControl x:Class="SO9735486.Views.SecondContentView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Label>Second content view</Label>
<Rectangle Fill="Blue" Width="100" Height="30"/>
</StackPanel>
</UserControl>
MainView.xaml:
<UserControl x:Class="SO9735486.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
<ComboBox DockPanel.Dock="Top" ItemsSource="{Binding ContentViewModels}" SelectedItem="{Binding SelectedContentViewModel}" DisplayMemberPath="DisplayName"/>
<ContentControl Content="{Binding SelectedContentViewModel}"/>
</DockPanel>
</UserControl>
Changes done for Windows1.xaml.vb only. The code bhind file should be as below. The answer for the problem is instead of callinf Canvas1.Clear(), set the visibilty of the added user controls to Windows.Visibility.Collapsed.
Window1.xaml.vb
Class Window1
Private U1 As Integer
Private U2 As Integer
Private Sub LstItem1_Selected(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Canvas1.Children.Item(U1).Visibility = Windows.Visibility.Visible
Canvas1.Children.Item(U2).Visibility = Windows.Visibility.Collapsed
End Sub
Private Sub LstItem2_Selected(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Canvas1.Children.Item(U2).Visibility = Windows.Visibility.Visible
Canvas1.Children.Item(U1).Visibility = Windows.Visibility.Collapsed
End Sub
Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
U1 = Canvas1.Children.Add(New UserControl1)
U2 = Canvas1.Children.Add(New UserControl2)
Canvas1.Children.Item(U1).Visibility = Windows.Visibility.Collapsed
Canvas1.Children.Item(U2).Visibility = Windows.Visibility.Collapsed
End Sub
End Class

Resources