C# Master Detail View - Reverting unsaved changes - c#

I'm creating CRUD application in C# with Caliburn.Micro and I have some Master Detail View that looks like that:
What i want to achieve is, when i make some changes(for example i change capacity from 47 to 50), and then select the other place, let's say Place 4 and select Place 5 again my capacity will be 47, not 50 like it is now.
I was thinking about OneTime binding, and manually firing binding to the viewmodel then, but viewModel should not have been aware of the view, so that seems like a bad idea. My code below.
XAML:
<DataGrid x:Name="Places"
Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"
Width="290"
HorizontalAlignment="Left"
CanUserReorderColumns="False" CanUserResizeColumns="False" IsReadOnly="True"
AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="False" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn Header="Place" Binding="{Binding Name, Mode=OneTime}" MinWidth="150"
Width="SizeToCells" />
</DataGrid.Columns>
</DataGrid>
<Grid Grid.Column="0" Grid.Row="2"
Width="290" Height="210"
HorizontalAlignment="Left" VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition Width="180" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="60" />
<RowDefinition Height="30" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Label Content="ID"
Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" />
<Label Content="Place*"
Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />
<Label Content="Address*"
Grid.Column="0" Grid.Row="2" VerticalAlignment="Top" />
<Label Content="Capacity*"
Grid.Column="0" Grid.Row="3" VerticalAlignment="Top" />
<Label Content="Comments"
Grid.Column="0" Grid.Row="4" VerticalAlignment="Top" />
<TextBox x:Name="SelectedPlace_Id"
Grid.Column="1" Grid.Row="0" VerticalAlignment="Top"
IsEnabled="False" />
<TextBox x:Name="SelectedPlace_Name"
Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" />
<TextBox x:Name="SelectedPlace_Address"
Grid.Column="1" Grid.Row="2"
Height="55" VerticalAlignment="Top"
TextWrapping="Wrap" />
<TextBox x:Name="SelectedPlace_Capacity"
Grid.Column="1" Grid.Row="3" VerticalAlignment="Top" />
<TextBox x:Name="SelectedPlace_Comments"
Grid.Column="1" Grid.Row="4" Height="55"
VerticalAlignment="Top"
TextWrapping="Wrap" />
</Grid>
<Button x:Name="DeletePlace" Content="Delete"
Grid.Column="0" Grid.Row="3"
Width="100" Height="30" Margin="0 0 110 0"
HorizontalAlignment="Right" VerticalAlignment="Top" />
<Button x:Name="SavePlace" Content="Save"
Grid.Column="0" Grid.Row="3"
Width="100" Height="30" Margin="0 0 5 0"
HorizontalAlignment="Right" VerticalAlignment="Top" />
ViewModel:
class PlacesTabViewModel : TabViewModel
{
#region Fields
private BindableCollection<Place> _places;
private Place _selectedPlace;
#endregion
#region Methods
public PlacesTabViewModel()
{
using (var ctx = new DbCtx(App.DatabasePath))
{
_places = new BindableCollection<Place>(ctx.Places.OrderBy(p => p.Name));
}
}
public override string ToString()
{
return "Places";
}
#endregion
#region Events
public bool CanDeletePlace => _selectedPlace != null;
public bool CanSavePlace => (_selectedPlace != null) && _selectedPlace.IsValid();
public void DeletePlace()
{
using (var ctx = new DbCtx(App.DatabasePath))
{
try
{
ctx.Entry(SelectedPlace).State = EntityState.Deleted;
ctx.SaveChanges();
}
catch (DbUpdateException)
{
//TODO: Error
return;
}
Places.Remove(SelectedPlace);
NotifyOfPropertyChange(nameof(Places));
NotifyOfPropertyChange(() => CanDeletePlace);
NotifyOfPropertyChange(() => CanSavePlace);
}
}
public void SavePlace()
{
using (var ctx = new DbCtx(App.DatabasePath))
{
try
{
ctx.Places.Attach(_selectedPlace);
ctx.Entry(_selectedPlace).State = EntityState.Modified;
ctx.SaveChanges();
}
catch
{
//TODO: Error
}
NotifyOfPropertyChange(nameof(Places));
}
}
#endregion
#region Properties
public BindableCollection<Place> Places
{
get { return _places; }
set
{
if (value != _places)
{
_places = value;
NotifyOfPropertyChange(nameof(Places));
}
}
}
public Place SelectedPlace
{
get { return _selectedPlace; }
set
{
if (value != _selectedPlace)
{
_selectedPlace = value;
if (_selectedPlace != null)
{
_selectedPlace.PropertyChanged += (sender, args) =>
{
NotifyOfPropertyChange(() => CanSavePlace);
};
}
NotifyOfPropertyChange(nameof(SelectedPlace));
NotifyOfPropertyChange(() => CanDeletePlace);
NotifyOfPropertyChange(() => CanSavePlace);
}
}
}
#endregion
}
ViewModel for the MainWindow
class MainWindowViewModel : PropertyChangedBase
{
#region Fields
private BindableCollection<TabViewModel> _tabs = new BindableCollection<TabViewModel>();
#endregion
public MainWindowViewModel()
{
_tabs.Add(new PlacesTabViewModel());
}
#region Properties
public BindableCollection<TabViewModel> Tabs
{
get { return _tabs; }
set
{
if (value != _tabs)
{
_tabs = value;
NotifyOfPropertyChange(nameof(Tabs));
}
}
}
#endregion
}

WPF doesn't know Normal properties. You either have to make it a dependency property, or in your case, your VM has to implement INotifyPropertyChanged. when the value changes it will automatically updated.
May be you didn't applied INotifyPropertyChanged property for SelectedPlace_Capacity.
I think that this is the issue.

Related

WPF restoring position in the Combobox

There is an Observablecollection Fathers that stores the ID-Firstname-Lastname father. How to make it so that when loading data from the child.lbs file, the ID value that is written in the file under word[4] is selected in the Combobox field? Item values are spelled out using XAML <Combobox "ItemsSource = {Binding Fathers}"/>
That is, so that when the file is loaded, the same values are restored as they were before the shutdown (the so-called Save/Load)
enter image description here
enter image description here
Father.cs
namespace LabelBase.Models
{
public class Father : INotifyPropertyChanged
{
private int _id;
public int FatherID
{
get => _id;
set
{
_id = value;
OnPropertyChanged();
}
}
private string _firstname;
public string Firstname
{
get => _firstname;
set
{
_firstname = value;
OnPropertyChanged();
}
}
private string _secondname;
public string Secondname
{
get => _secondname;
set
{
_secondname = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
Child.cs
namespace LabelBase.Models
{
public class Child : INotifyPropertyChanged
{
private int _id;
public int ChildID
{
get => _id;
set
{
_id = value;
OnPropertyChanged();
}
}
private string _first;
public string Firstname
{
get => _first;
set
{
_first = value;
OnPropertyChanged();
}
}
private string _second;
public string Secondname
{
get => _second;
set
{
_second = value;
OnPropertyChanged();
}
}
private Father _father;
public Father Father
{
get => _father;
set
{
_father = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
child.lbs contents:
13;Ken;Hollow;83
10;Fill;Kenory;93
father.lbs contents:
83;Frank;Malkov
93;Jack;Miles
MainWindow.xaml:
<Grid>
<TabControl>
<TabItem Header="Save">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Save" Margin="100" Height="50" Command="{Binding SaveButton}"/>
<Button Grid.Column="1" Content="Load" Margin="100" Height="50" Command="{Binding LoadButton}"/>
</Grid>
</TabItem>
<TabItem Header="Child">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Margin="5,5,5,50" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Height="25" Margin="5" Text="{Binding ElementName=ChildGrid, Path=Columns[0].Header, StringFormat={}{0}: }" TextAlignment="Right"/>
<TextBlock Grid.Column="0" Grid.Row="1" Height="25" Margin="5" Text="{Binding ElementName=ChildGrid, Path=Columns[1].Header, StringFormat={}{0}: }" TextAlignment="Right"/>
<TextBlock Grid.Column="0" Grid.Row="2" Height="25" Margin="5" Text="{Binding ElementName=ChildGrid, Path=Columns[2].Header, StringFormat={}{0}: }" TextAlignment="Right"/>
<TextBlock Grid.Column="0" Grid.Row="3" Height="25" Margin="5" Text="{Binding ElementName=ChildGrid, Path=Columns[3].Header, StringFormat={}{0}: }" TextAlignment="Right"/>
<TextBox Grid.Column="1" Grid.Row="0" Height="25" Text="{Binding SelectedChildren.ChildID}" Margin="5"/>
<TextBox Grid.Column="1" Grid.Row="1" Height="25" Text="{Binding SelectedChildren.Firstname}" Margin="5"/>
<TextBox Grid.Column="1" Grid.Row="2" Height="25" Text="{Binding SelectedChildren.Secondname}" Margin="5"/>
<ComboBox Grid.Column="1" Grid.Row="3" Height="25" ItemsSource="{Binding Fathers}" SelectedItem="{Binding SelectedChildren.Father}" Margin="5">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="Firstname"/>
<Binding Path="Secondname"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
<DataGrid Name="ChildGrid" Grid.Column="1" Margin="0,10,10,10" AutoGenerateColumns="False" ItemsSource="{Binding Children}" SelectedItem="{Binding SelectedChildren}">
<DataGrid.Columns>
<DataGridTextColumn Width="auto" Header="ID" Binding="{Binding ChildID}"/>
<DataGridTextColumn Width="auto" Header="Firstname" Binding="{Binding Firstname}"/>
<DataGridTextColumn Width="auto" Header="Secondname" Binding="{Binding Secondname}"/>
<DataGridTextColumn Width="auto" Header="Father" Binding="{Binding Father.FatherID}"/>
</DataGrid.Columns>
</DataGrid>
<Button Height="25" Margin="10,0,10,20" Content="Add Child" Command="{Binding AddChildButton}" VerticalAlignment="Bottom"/>
</Grid>
</TabItem>
<TabItem Header="Father">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Margin="5,5,5,50" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Height="25" Margin="5" Text="{Binding ElementName=FatherGrid, Path=Columns[0].Header, StringFormat={}{0}: }" TextAlignment="Right"/>
<TextBlock Grid.Column="0" Grid.Row="1" Height="25" Margin="5" Text="{Binding ElementName=FatherGrid, Path=Columns[1].Header, StringFormat={}{0}: }" TextAlignment="Right"/>
<TextBlock Grid.Column="0" Grid.Row="2" Height="25" Margin="5" Text="{Binding ElementName=FatherGrid, Path=Columns[2].Header, StringFormat={}{0}: }" TextAlignment="Right"/>
<TextBox Grid.Column="1" Grid.Row="0" Height="25" Text="{Binding SelectedFathers.FatherID}" Margin="5"/>
<TextBox Grid.Column="1" Grid.Row="1" Height="25" Text="{Binding SelectedFathers.Firstname}" Margin="5"/>
<TextBox Grid.Column="1" Grid.Row="2" Height="25" Text="{Binding SelectedFathers.Secondname}" Margin="5"/>
</Grid>
<DataGrid Name="FatherGrid" Grid.Column="1" Margin="0,10,10,10" AutoGenerateColumns="False" ItemsSource="{Binding Fathers}" SelectedItem="{Binding SelectedFathers}">
<DataGrid.Columns>
<DataGridTextColumn Width="auto" Header="ID" Binding="{Binding FatherID}"/>
<DataGridTextColumn Width="auto" Header="Firstname" Binding="{Binding Firstname}"/>
<DataGridTextColumn Width="auto" Header="Secondname" Binding="{Binding Secondname}"/>
</DataGrid.Columns>
</DataGrid>
<Button Height="25" Margin="10,0,10,20" Content="Add Father" Command="{Binding AddFatherButton}" VerticalAlignment="Bottom"/>
</Grid>
</TabItem>
</TabControl>
</Grid>
ContextVIew.cs:
using LabelBase.Models;
namespace LabelBase
{
public class ContextView : INotifyPropertyChanged
{
public ObservableCollection<Father> Fathers { get; }
public ObservableCollection<Child> Children { get; }
private Father _selectedFather;
public Father SelectedFathers
{
get => _selectedFather;
set
{
_selectedFather = value;
OnPropertyChanged();
}
}
private RelayCommand _addFatherButton;
public RelayCommand AddFatherButton
{
get
{
return _addFatherButton ?? (_addFatherButton = new RelayCommand(obj =>
{
Father f = new Father();
Random r = new Random();
f.FatherID = r.Next(99);
Fathers.Insert(Fathers.Count, f);
SelectedFathers = f;
}));
}
}
private Child _selectedChild;
public Child SelectedChildren
{
get => _selectedChild;
set
{
_selectedChild = value;
OnPropertyChanged();
}
}
private RelayCommand _addChildButton;
public RelayCommand AddChildButton
{
get
{
return _addChildButton ?? (_addChildButton = new RelayCommand(obj =>
{
Child c = new Child();
Random r = new Random();
c.ChildID = r.Next(99);
Children.Insert(Children.Count, c);
SelectedChildren = c;
}));
}
}
private RelayCommand _save;
public RelayCommand SaveButton
{
get
{
return _save ?? (_save = new RelayCommand(obj =>
{
StreamWriter swChild = new StreamWriter($"{AppDomain.CurrentDomain.BaseDirectory}/save/child.lbs", false);
StreamWriter swFather = new StreamWriter($"{AppDomain.CurrentDomain.BaseDirectory}/save/father.lbs", false);
foreach(Child item in Children)
{
string sandwich = $"{item.ChildID};{item.Firstname};{item.Secondname};{item.Father.FatherID}";
swChild.WriteLine(sandwich);
}
swChild.Close();
foreach (Father item in Fathers)
{
string sandwich = $"{item.FatherID};{item.Firstname};{item.Secondname}";
swFather.WriteLine(sandwich);
}
swFather.Close();
MessageBox.Show("Complete");
}));
}
}
private RelayCommand _load;
public RelayCommand LoadButton
{
get
{
return _load ?? (_load = new RelayCommand(obj =>
{
StreamReader srChild = new StreamReader($"{AppDomain.CurrentDomain.BaseDirectory}/save/child.lbs", false);
StreamReader srFather = new StreamReader($"{AppDomain.CurrentDomain.BaseDirectory}/save/father.lbs", false);
string lineChild, lineFather;
while((lineFather = srFather.ReadLine()) != null)
{
string[] word = lineFather.Split(';');
Father f = new Father();
f.FatherID = int.Parse(word[0]);
f.Firstname = word[1];
f.Secondname = word[2];
Fathers.Insert(Fathers.Count, f);
}
while((lineChild = srChild.ReadLine()) != null)
{
string[] word = lineChild.Split(';');
Child c = new Child();
c.ChildID = int.Parse(word[0]);
c.Firstname = word[1];
c.Secondname = word[2];
//c.Father.FatherID = int.Parse(word[3]);
Children.Insert(Children.Count, c);
}
srChild.Close();
MessageBox.Show("Complete");
}));
}
}
public ContextView(){
Fathers = new ObservableCollection<Father>();
Children = new ObservableCollection<Child>();
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
There is a Project: https://github.com/RodKingroo/FatherChild
Who will help, thanks :)
Thanks, #BionicCode 4 ur help
Answer ContextWiew.cs:
using (StreamReader srChild = new StreamReader($"{AppDomain.CurrentDomain.BaseDirectory}/save/child.lbs")) {
lineChild = srChild.ReadLine();
while ((lineChild = srChild.ReadLine()) != null)
{
string[] word = lineChild.Split(';');
Child c = new Child();
c.ChildID = int.Parse(word[0]);
c.Firstname = word[1];
p.Secondname = word[2];
foreach (Father item in Father)
{
if (item.FatherID == int.Parse(word[5])) p.Father = item;
}
Children.Add(c);
SelectedChildren = c;
}
srChild.Close();
}

INotifyPropertyChanged is not refreshing my listview in WPF MVVM entity

I have one action in my view model to add record in to entity frame work.I have one action to display the records in the view like this :
private void FillProspects()
{
var q = (from a in ctx2.Prospects// 'ctx' is the object of entity
select a).ToList();
this.Prospects = q; // 'Porspects' is a collection of entity class this I have bound with my List view in my view
}
This will be called in construction of my view model.as a result the list view in my view will be showing the records .
I have one add record action in my view model..I have created properties in my view model corresponding to properties generated in the entity class for example:
private String _FirstName;
public String FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
And my add record action in the view model is :
public void Add1()
{
newprospect = new Prospect();
newprospect.ID = Guid.NewGuid();
newprospect.FirstName = FirstName;
newprospect.LastName = LastName;
newprospect.Address = Address;
newprospect.State = State;
newprospect.City = City;
newprospect.ZIP = ZIP;
prospect = newprospect;
ctx2.AddToProspects(prospect);
FillProspects();
//RaisePropertyChanged("Prospects");
}
I have inherited the : INotifyPropertyChanged and imported it's
using System.Windows.Input;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string property) { PropertyChanged(this, new PropertyChangedEventArgs(property)); }
But my notification is not refreshing my view Listview records after adding record .so I just call the fill records method 'FillProspects' in the addrecord action..Is this right way of doing MVVM .Why my Listview is not getting refreshed after add record action where I am missing?I have tried with
RaisePropertyChanged("Prospects");in the Add record action...but it is not refreshing .So I just called fill method action again
My complete view model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Input;
using System.Collections.ObjectModel;
namespace Wpfentity3
{
public class frmProspects_VM : INotifyPropertyChanged
{
TestsEntities ctx2 = new TestsEntities();
public ObservableCollection<Prospect> prospects { get; set; }
//This is the collection where records - er, entities - returned by a query are stored;
//Prospect is the generated class that defines a record - er,
//an entity as well as the query for that table.
private CommandMap _Commands;
public CommandMap Commands { get { return _Commands; } }
Prospect newprospect;
//This holds a new prospect that is created and then added to the prospects collection
private Prospect _prospect;
public Prospect prospect {
get
{
return _prospect;
}
set
{
_prospect = value;
RaisePropertyChanged("prospect");
}
}
//prospect is the object that holds the current record from the Prospects table.
//MainWindow controls are bound to this object
public frmProspects_VM()
{
//FillProspects();
ctx2 = new TestsEntities();
//This instantiates the EntityManager class ;
prospects = new ObservableCollection<Prospect>();
//This instantiates the prospects collection of Prospect records - er, entities;
_Commands = new CommandMap();
_Commands.AddCommand("Add", x => Add1());
}
private ObservableCollection<Prospect> _prospects;
public ObservableCollection<Prospect> Prospects
{
get
{
return _prospects;
}
set
{
_prospects = value;
RaisePropertyChanged("Prospects");
}
}
private String _FirstName;
public String FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
private String _LastName;
public String LastName
{
get
{
return _LastName;
}
set
{
_LastName = value;
}
}
private String _Address;
public String Address
{
get
{
return _Address;
}
set
{
_Address = value;
}
}
private String _State;
public String State
{
get
{
return _State;
}
set
{
_State = value;
}
}
private String _City;
public String City
{
get
{
return _City;
}
set
{
_City = value;
}
}
private String _ZIP;
public String ZIP
{
get
{
return _ZIP;
}
set
{
_ZIP = value;
}
}
public void Add1()
{
newprospect = new Prospect();
newprospect.ID = Guid.NewGuid();
newprospect.FirstName = FirstName;
newprospect.LastName = LastName;
newprospect.Address = Address;
newprospect.State = State;
newprospect.City = City;
newprospect.ZIP = ZIP;
prospect = newprospect;
ctx2.AddToProspects(prospect);
Prospects.Add(newprospect);
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string property) { PropertyChanged(this, new PropertyChangedEventArgs(property)); }
}
}
My view xamal:
<Window x:Class="Wpfentity3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStartupLocation="CenterScreen"
Title="Prospects"
Height="482" Width="500" MaxWidth="500" MaxHeight="600"
xmlns:cusns="clr-namespace:Wpfentity3">
<StackPanel Height="290" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" >
<Label
Content="Prospects"
BorderBrush="Blue" BorderThickness="1"
HorizontalAlignment="Left" VerticalAlignment="Top"
FontSize="24" FontFamily="Comic Sans MS"
Padding="13,3,13,9" Margin="5"
Foreground="Purple" Background="LemonChiffon" />
<Label
Content="{Binding Path=label}" Foreground="Red" FontSize="14"
HorizontalAlignment="Right" VerticalAlignment="Center"
Height="auto" Margin="180,0,10,0" />
</StackPanel>
<Grid
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="120" Width="475" >
<Grid.RowDefinitions>
<RowDefinition Height="25*" />
<RowDefinition Height="25*" />
<RowDefinition Height="25*" />
<RowDefinition Height="25*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="135*" />
<ColumnDefinition Width="45*" />
<ColumnDefinition Width="32*" />
<ColumnDefinition Width="57*" />
<ColumnDefinition Width="118*" />
</Grid.ColumnDefinitions>
<Label
Content="First name"
Grid.Row="0" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtFirstName"
Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=FirstName}"
Width="130" />
<Label
Content="Last name"
Grid.Row="1" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtLastName"
Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding LastName}"
Width="130" />
<Label
Content="Address"
Grid.Row="2" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtAddress"
Grid.Row="2" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Address}"
Width="300" Grid.ColumnSpan="5" />
<Label
Content="City"
Grid.Row="3" Grid.Column="0" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtCity"
Grid.Row="3" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding City}"
Width="130" />
<Label
Content="State"
Grid.Row="3" Grid.Column="2" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtState"
Grid.Row="3" Grid.Column="3" Width="30" MaxLength="2" CharacterCasing="Upper" Text="{Binding State}"
HorizontalAlignment="Left" VerticalAlignment="Center" />
<Label
Content="ZIP code"
Grid.Row="3" Grid.Column="4" Margin="0,0,5,0"
HorizontalAlignment="Right" VerticalAlignment="Center" />
<TextBox Name="txtZIP"
Grid.Row="3" Grid.Column="5" MaxLength="10"
HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding ZIP}"
Width="90" />
</Grid>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button Name="btnFind"
Content="_Find"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnAdd"
Content="_Add" Command="{Binding Commands.Add}"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnEdit"
Content="_Edit"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnDelete"
Content="_Delete"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnSave"
Content="_Save"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnCancel"
Content="_Cancel"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
<Button Name="btnClose"
Content="Cl_ose"
Width="auto" Margin="5,0,5,0" Padding="10,0,10,0"
/>
</StackPanel>
<StackPanel Height="34" Margin="10">
<Grid Margin="10">
<ListView Name="lvprospects" ItemsSource="{Binding Prospects}" Margin="0,0,0,-200">
<ListView.View>
<GridView>
<GridViewColumn Header="FirstName" Width="120" DisplayMemberBinding="{Binding FirstName}" />
<GridViewColumn Header="LastName" Width="50" DisplayMemberBinding="{Binding LastName}" />
<GridViewColumn Header="Address" Width="50" DisplayMemberBinding="{Binding Address}" />
<GridViewColumn Header="City" Width="50" DisplayMemberBinding="{Binding City}" />
<GridViewColumn Header="State" Width="50" DisplayMemberBinding="{Binding State}" />
<GridViewColumn Header="ZIP" Width="50" DisplayMemberBinding="{Binding ZIP}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</StackPanel>
</StackPanel>
Change the type of the Prospects property from List<Prospect> to ObservableCollection<Prospect>:
private ObservableCollection<Prospect> _prospects = new ObservableCollection<Prospect>();
public ObservableCollection<Prospect> Prospects
{
get
{
return _prospects;
}
set
{
_prospects = value;
RaisePropertyChanged("Prospects");
}
}
And add the new Prospect object to this collection as well in your Add1 method:
public void Add1()
{
newprospect = new Prospect();
newprospect.ID = Guid.NewGuid();
newprospect.FirstName = FirstName;
newprospect.LastName = LastName;
newprospect.Address = Address;
newprospect.State = State;
newprospect.City = City;
newprospect.ZIP = ZIP;
prospect = newprospect;
ctx2.AddToProspects(prospect);
Prospects.Add(newprospect);
}
Just adding it to the DbContext doesn't affect the ListView.
It is fine to add the new item to the DB and then retrieve again the collection with the same refresh method FillProspects:
what you're doing is basically correct.
If you're going to bind a view to a collection in your ViewModel, I suggest using an ObservableCollection.
The ObservableCollection implements INotifyCollectionChanged, it notifies the view when elements are added or removed.
With this you should not need your "FillProspects" method and your "RaisePropertyChanged("Prospects")".
If you want more information I suggest posting how you bind in your XAML and also how you construct your "Prospects" object (we don't even know what type it is, I just assume it isn't an ObservableCollection).
EDIT :
you bind your ListView to "Prospects", but in your ViewModel, I see that "Prospects" is of type "List", it needs to be "ObservableCollection". I see that you have an ObservableCollection named "prospects", but you don't use it anywhere. Could this be the issue ?

WPF MVVM properties binding not working properly

I have created a view model which has a single property for a student model, that I am then binding to a control in my XAML. But nothing is appearing when I execute the application.
I am setting data context in my app.xaml.cs as follows:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Registrationformusinemvvm.MainWindow window = new MainWindow();
VMUser VM = new VMUser();
window.DataContext = VM;
window.Show();
}
Why is the binding not working?
This is my view model:
public class VMUser:BaseClass
{
private student _currentStudent;
public student CurrentStudent
{
get { return _currentStudent; }
set {
_currentStudent = value;
OnPropertyChanged("CurrentStudent");
}
}
}
My Student model class:
public class student:BaseClass
{
private string name="sumit";
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}
private int rollNum;
public int RollNum
{
get { return rollNum; }
set { rollNum = value;OnPropertyChanged("RollNum"); }
}
private int phNum;
public int PhNum
{
get { return phNum; }
set { phNum = value;OnPropertyChanged("PhNum"); }
}
private string sub;
public string Sub
{
get { return sub; }
set { sub = value;OnPropertyChanged("Sub"); }
}
}
My XAML:
<Window x:Class="Registrationformusinemvvm.MainWindow"
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:Registrationformusinemvvm"
xmlns:vm="clr-namespace:Registrationformusinemvvm.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<!--<Window.DataContext>
<vm:VMUser/>
</Window.DataContext>-->
<Window.Resources>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name" Grid.Column="0" Grid.Row="0" FontSize="14"
FontWeight="Bold" VerticalAlignment="Center"
HorizontalAlignment="Center"/>
<TextBlock Text="Roll Number" Grid.Column="0" Grid.Row="1" FontSize="14"
FontWeight="Bold" VerticalAlignment="Center"
HorizontalAlignment="Center"/>
<TextBlock Text="Subject" Grid.Column="0" Grid.Row="2" FontSize="14"
FontWeight="Bold" VerticalAlignment="Center"
HorizontalAlignment="Center"/>
<TextBlock Text="Phone Number" Grid.Column="0" Grid.Row="3"
FontSize="14" FontWeight="Bold" VerticalAlignment="Center"
HorizontalAlignment="Center"/>
<TextBox Name="tbName" Text="{Binding CurrentStudent.Name,Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="0"
Width="120" Height="30" HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBox Name="tbRollnum" Text="{Binding CurrentStudent.RollNum}"
Grid.Column="1" Grid.Row="1" Width="120" Height="30"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Name="tbSub" Text="{Binding CurrentStudent.Sub}"
Grid.Column="1" Grid.Row="2" Width="120" Height="30"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Name="tbPh" Text="{Binding CurrentStudent.PhNum}"
Grid.Column="1" Grid.Row="3" Width="120" Height="30"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button Name="tbSubmit" Content="Submit" Grid.ColumnSpan="3"
Grid.Row="4" Height="30" Width="100" HorizontalAlignment="Center"/>
</Grid>
</Window>
My guess is that your binding isn't working because your _currentStudent is null by default. Initialize your _currentStudent if null.
public student CurrentStudent
{
get { return _currentStudent = (_currentStudent ?? new student()); }
set
{
_currentStudent = value; OnPropertyChanged("CurrentStudent");
}
}
You need to add OnPropertyChanged in your model class.
void OnPropertyChanged(string prop)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
public event PropertyChangedEventHandler PropertyChanged;
As per your above code you cant assigned the value to CurrentStudent Property so
can you please check do you have the value to CurrentStudent property.
Thank you for your question
Remove StartupUri="YourXamlFile.xaml" from App.Xaml

Select items from list and add them in a list?

Hi I am working on a networking application for which I am using C# WPF and MVVM pattern. This would be a fast configuration application so that user can configure a device from application. The problem of confusion is that I want want to take information about vlans and there could be multiple vlans a user can create. So I need to take multiple information from user at the same time and in the end I will configure all the values via telnet command. What would be the possible and simple way of taking multiple inputs from user and store it till end so that it could be configured correctly?
Suggestions would be greatly appreciable.
My code for VLANS ViewModel is:
public class VLANSViewModel : WizardPageViewModelBase
{
#region Fields
#endregion // end region fields
#region Constructor
public VLANSViewModel(ConfigurationLibrary configuration)
: base(configuration)
{
VlanIP1 = "192";
VlanIP2 = "168";
VlanIP3 = "1";
VlanIP4 = "1";
}
#endregion
#region Properties
public string VlanName
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanName;
}
set
{
if (String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanName, value))
{
return;
}
this.ConfigurationLibrary.ConfigLibraryVlanName = value;
this.OnPropertyChanged("VlanName");
}
}
public string VlanID
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanName;
}
set
{
if (String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanName, value))
{
return;
}
this.ConfigurationLibrary.ConfigLibraryVlanName = value;
this.OnPropertyChanged("VlanID");
}
}
public string VlanIP1
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanIp1;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanIp1, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanIp1 = value;
this.OnPropertyChanged("VlanIP1");
}
}
}
public string VlanIP2
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanIp2;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanIp2, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanIp2 = value;
this.OnPropertyChanged("VlanIP2");
}
}
}
public string VlanIP3
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanIp3;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanIp3, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanIp3 = value;
this.OnPropertyChanged("VlanIP3");
}
}
}
public string VlanIP4
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanIp4;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanIp4, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanIp4 = value;
this.OnPropertyChanged("VlanIP4");
}
}
}
public string VlanDefaultRoute1
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute1;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute1, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute1 = value;
this.OnPropertyChanged("VlanDefaultRoute1");
}
}
}
public string VlanDefaultRoute2
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute2;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute2, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute2 = value;
this.OnPropertyChanged("VlanDefaultRoute2");
}
}
}
public string VlanDefaultRoute3
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute3;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute3, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute3= value;
this.OnPropertyChanged("VlanDefaultRoute3");
}
}
}
public string VlanDefaultRoute4
{
get
{
return this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute4;
}
set
{
if (!String.Equals(this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute4, value))
{
this.ConfigurationLibrary.ConfigLibraryVlanDefaultRoute4 = value;
this.OnPropertyChanged("VlanDefaultRoute4");
}
}
}
#endregion // end region fields
public override string DisplayName
{
get
{
return Strings.PageDisplayName_VLAN;
}
}
#region Methods
internal override bool IsValid()
{
return true;
}
#endregion
}
And my view for VLANS is :
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Content="VLAN NAME"
Foreground="Black"
Opacity="0.8"
/>
<ComboBox
Grid.Row="0"
Grid.Column="1"
Margin="0,5,0,0"
Height="25"
Foreground="Black"
Opacity="0.8"
Width="Auto"
Text="{Binding VlanName, UpdateSourceTrigger=PropertyChanged}"
/>
<Label
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Content="VLAN ID"
Foreground="Black"
Opacity="0.8"
/>
<TextBox
Grid.Row="1"
Grid.Column="1"
Margin="0,5,0,0"
Height="25"
Foreground="Black"
Opacity="0.8"
Width="Auto"
Text="{Binding VlanID, UpdateSourceTrigger=PropertyChanged}"
/>
<Label
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Content="IP FOR VLAN"
Foreground="Black"
Opacity="0.8"
/>
<Grid
Grid.Column="1"
Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBox
Grid.Row="2"
Grid.Column="0"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanIP1, UpdateSourceTrigger=PropertyChanged}"
/>
<TextBox
Grid.Row="2"
Grid.Column="1"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanIP2, UpdateSourceTrigger=PropertyChanged}"
/>
<TextBox
Grid.Row="2"
Grid.Column="2"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanIP3, UpdateSourceTrigger=PropertyChanged}"
/>
<TextBox
Grid.Row="2"
Grid.Column="3"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanIP4, UpdateSourceTrigger=PropertyChanged}"
/>
</Grid>
<Label
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Content="DEFAULT ROUTE"
Foreground="Black"
Opacity="0.8"
/>
<Grid
Grid.Row="3"
Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBox
Grid.Row="2"
Grid.Column="0"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanDefaultRoute1, UpdateSourceTrigger=PropertyChanged}"
/>
<TextBox
Grid.Row="2"
Grid.Column="1"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanDefaultRoute2, UpdateSourceTrigger=PropertyChanged}"
/>
<TextBox
Grid.Row="2"
Grid.Column="2"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanDefaultRoute3, UpdateSourceTrigger=PropertyChanged}"
/>
<TextBox
Grid.Row="2"
Grid.Column="3"
Margin="5"
VerticalAlignment="Center"
MaxLength="3"
Width="30"
Foreground="Black"
Opacity="0.8"
Text="{Binding VlanDefaultRoute4, UpdateSourceTrigger=PropertyChanged}"
/>
</Grid>
</Grid>
</UserControl>
I want to save multiple values for VLANS values at one time. Now any suggestions?
I think you are looking for a good introduction to get from scratch to an MVVM application that can handle models correctly. In that case I recommend to use a "getting started with MVVM" guid such as this one in Catel.

Having problems with WPF Databinding

I have 2 objects, a Customer and a Store. There are multiple store locations, each customer has a property called PreferredStoreId (int?) which relates to a Store's Id (int).
In a WPF application I am attempting to build a form that allows a customer to be edited. A combo box exists on this form which is filled with Stores to act as a way of displaying the currently set PreferredStore and a way of changing the preferred store.
My problem is, whilst I can populate the combobox, I cannot get two way binding between the Customer.PreferredId (the object set to the UserControl's datacontext) and the combobox's SelectedItem (a Store Object)'s .Id property.
Here Is my XAML to help make sense:
<UserControl x:Class="ucCustomerEditor"
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:localViewModels="clr-namespace:ViewModels"
xmlns:qc="clr-namespace:QuickConverter;assembly=QuickConverter"
mc:Ignorable="d" d:DesignWidth="750" Height="334">
<UserControl.DataContext>
<localViewModels:CustomerViewModel x:Name="customerViewModel" />
</UserControl.DataContext>
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Height="26" Width="50" Content="Save" Margin="5,10" Click="UserAction_Save" />
<Button Height="26" Width="50" Content="Cancel" Margin="10,10" Click="UserAction_Cancel" />
</StackPanel>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding FirstName}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="First Name:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding LastName}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Last Name:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding EmailAddress}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Email Address:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding PhoneNumber}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Phone Number:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ComboBox Name="cbPreferredStore"
ItemsSource="{Binding Stores}" DisplayMemberPath="DisplayName" Height="23" Margin="10,0,0,0" VerticalAlignment="Top"
HorizontalAlignment="Stretch" Grid.Column="1" SelectedValue="{Binding ElementName=customerViewModel, Path=PreferredStoreId}">
<ComboBox.DataContext>
<localViewModels:StoreListViewModel />
</ComboBox.DataContext>
</ComboBox>
<Label Content="Preferred Store:" Margin="10,0" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
<Grid Height="26" Margin="10" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="209"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding Password}" Height="23" Margin="10,0,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1"/>
<Label Content="Password:" Margin="10,0" VerticalAlignment="Top" Height="26" FontWeight="Bold"/>
</Grid>
</StackPanel>
StoreViewModel code:
ublic class StoreViewModel : BaseViewModel
{
private enum Modes { CREATE, UPDATE }
private Modes _mode;
private Store _store;
public string DisplayName
{
get { return string.Format("{0} ({1})", this._store.LocationName, this._store.Id); }
}
public int Id
{
get { return this._store.Id; }
set
{
this._store.Id = value;
notifyPropertyChanged("Id");
notifyPropertyChanged("DisplayName");
}
}
public string LocationName
{
get { return this._store.LocationName; }
set
{
this._store.LocationName = value;
notifyPropertyChanged("LocationName");
notifyPropertyChanged("DisplayName");
}
}
public string ImageURL
{
get { return this._store.ImageURL; }
set
{
this._store.ImageURL = value;
notifyPropertyChanged("ImageURL");
}
}
public string AddressLine1
{
get { return this._store.AddressLine1; }
set
{
this._store.AddressLine1 = value;
notifyPropertyChanged("AddressLine1");
}
}
public string AddressLine2
{
get { return this._store.AddressLine2; }
set
{
this._store.AddressLine2 = value;
notifyPropertyChanged("AddressLine2");
}
}
public string AddressLine3
{
get { return this._store.AddressLine3; }
set
{
this._store.AddressLine3 = value;
notifyPropertyChanged("AddressLine3");
}
}
public string Suburb
{
get { return this._store.Suburb; }
set
{
this._store.Suburb = value;
notifyPropertyChanged("Suburb");
}
}
public string State
{
get { return this._store.State; }
set
{
this._store.State = value;
notifyPropertyChanged("State");
}
}
public string Postcode
{
get { return this._store.Postcode; }
set
{
this._store.Postcode = value;
notifyPropertyChanged("Postcode");
}
}
public string Country
{
get { return this._store.Country; }
set
{
this._store.Country = value;
notifyPropertyChanged("Country");
}
}
public string PhoneNumber
{
get { return this._store.PhoneNumber; }
set
{
this._store.PhoneNumber = value;
notifyPropertyChanged("PhoneNumber");
}
}
public string EmailAddress
{
get { return this._store.EmailAddress; }
set
{
this._store.EmailAddress = value;
notifyPropertyChanged("EmailAddress");
}
}
public static explicit operator StoreViewModel(EasyDayTea.Store store)
{
return new StoreViewModel(store) { _mode = Modes.UPDATE };
}
public StoreViewModel()
{
_store = new Store();
_mode = Modes.CREATE;
}
public StoreViewModel(Store store)
{
_store = store;
_mode = Modes.UPDATE;
}
public void Cancel()
{
if (_mode == Modes.CREATE)
{
_store = new Store() { };
}
else
{
EasyDayTea.EasyDayTeaClient client = new EasyDayTeaClient();
_store = client.FetchStore(App.AppUserTeaCredental, _store.Id);
client.Close();
}
notifyAll();
}
public void Save()
{
try
{
EasyDayTeaClient client = new EasyDayTeaClient();
if (_mode == Modes.CREATE)
{
client.AddStore(App.AppUserTeaCredental, ImageURL, LocationName, AddressLine1, AddressLine2, AddressLine3, Suburb, State, Postcode, Country, PhoneNumber, EmailAddress);
}
else
{
client.SetStore(App.AppUserTeaCredental, Id, ImageURL, LocationName, AddressLine1, AddressLine2, AddressLine3, Suburb, State, Postcode, Country, PhoneNumber, EmailAddress);
}
client.Close();
MessageBox.Show("Your customer was saved.");
if (_mode == Modes.CREATE)
{
_store = new Store();
notifyAll();
}
else
{
//do nothing.
}
}
catch (Exception ex)
{
MessageBox.Show("There was a problem saving your customer: \r\n" + ex.Message);
}
}
internal void notifyAll()
{
notifyPropertyChanged("Id");
notifyPropertyChanged("LocationName");
notifyPropertyChanged("ImageURL");
notifyPropertyChanged("AddressLine1");
notifyPropertyChanged("AddressLine2");
notifyPropertyChanged("AddressLine3");
notifyPropertyChanged("Suburb");
notifyPropertyChanged("State");
notifyPropertyChanged("Postcode");
notifyPropertyChanged("Country");
notifyPropertyChanged("PhoneNumber");
notifyPropertyChanged("EmailAddress");
notifyPropertyChanged("DisplayName");
}
}
StoreListViewModel Code:
public class StoreListViewModel : BaseViewModel
{
private List<StoreViewModel> _stores;
public List<StoreViewModel> Stores
{
get { return this._stores; }
set
{
this._stores = value;
notifyPropertyChanged("Stores");
}
}
public StoreListViewModel()
{
EasyDayTea.EasyDayTeaClient client = new EasyDayTea.EasyDayTeaClient();
_stores = client.GetStores(App.AppUserTeaCredental).Select(s => (StoreViewModel)s).ToList();
client.Close();
}
}
I suppose that PreferredStoreId property in CustomerViewModel correctly implement the INotifyPropertyChanged interface.
If it's true, then you need change the SelectedValue to SelectedItem of your ComboBox, because SelectedItem property returns the entire object which it current selected. However, the SelectedValuePath property and the SelectedValue uses together as an alternative to the SelectedItem property and as I understand it was not your choice.
Also here:
SelectedValue="{Binding ElementName=customerViewModel, Path=PreferredStoreId}"
Not need ElementName, because a CustomerViewModel set the DataContext assigned by default.

Categories