WPF-MVVM: Adding New Entity - wpf

In a MVVM LOB application where data is persisted via EF service layer I have the following WPF EmployeeView which displays Employee Data via binding to Employee Model object contained in the EmployeeViewModel (Employee object is populated in controller class and persisted through the same class) :
here is xaml:
{
<TextBlock Grid.Column="0" Grid.Row="0" Text="ID:" />
<TextBox Grid.Column="1" Grid.Row="0"
Text="{Binding Employee.ID,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="50" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="First Name:" />
<TextBox Grid.Column="1" Grid.Row="1"
Text="{Binding Employee.FirstName,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="Last Name:" />
<TextBox Grid.Column="1" Grid.Row="2"
Text="{Binding Employee.LastName,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" />
<TextBlock Grid.Column="0" Grid.Row="4" Text="Department:" />
<ComboBox Grid.Column="1" Grid.Row="4" Width="150" SelectedValuePath="."
SelectedItem="{Binding Employee.Department,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Employee.DepartmentLookup}" DisplayMemberPath="DepartmentName" />
<TextBlock Grid.Column="0" Grid.Row="6" Text="Birth Date:" />
<DatePicker Grid.Column="1" Grid.Row="6"
SelectedDate="{Binding Employee.BirthDate,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Grid.Column="0" Grid.Row="7" Text="Hire Date:" />
<DatePicker Grid.Column="1" Grid.Row="7"
SelectedDate="{Binding Employee.HireDate,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button Height="25" Width="50" Grid.Column="1" Grid.Row="8" Command="{Binding Path=NewEmpCommand}">
<TextBlock Margin="1">New</TextBlock>
</Button>
<Button Margin="150,5,5,5" Height="25" Width="50" Grid.Column="1" Grid.Row="8"
Command="{Binding Path=AddEmpCommand}">
<TextBlock Margin="1">Add</TextBlock>
</Button>
}
and the ViewModel
public class EmployeeViewModel : INotifyPropertyChanged
{
//NewEmpCommand
private DelegateCommand _newEmpCommand;
public DelegateCommand NewEmpCommand
{
get
{
return _newEmpCommand??
(_newEmpCommand= new DelegateCommand(NewEmployee));
}
}
//AddEmpCommand
private DelegateCommand _addEmpCommand;
public DelegateCommand AddEmpCommand
{
get
{
return _addEmpCommand??
(_addEmpCommand= new DelegateCommand(AddEmployee));
}
}
//ctor-------------------------------------------------------------------------
public EmployeeViewModel ()
{
Initialize();
}
private void Initialize()
{
//
}
private void NewEmployee()
{
this.Employee = null;
}
//-------------------------------------------------------------------------
void AddEmployee()
{
//here I send the Employee Model object to the service layer to be persisted
}
//Binding----------------------------------------------------------------------
private Employee _employee;
public Employee Employee
{
get { return _employee; }
set
{
if (_employee!= value)
{
_employee= value;
NotifyPropertyChanged("Employee");
}
}
}
//---------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I omitted the unnecessary details. Now I want to click New button to clear all the controls so I use the statement "this.Employee = null;" (correct me if it is not the right way)
Then I want to enter the new value into the controls where (to my understanding) it should be assigned to the Employee model object.
to the questions:
1.is this the right way to clear the controls preparing for entering new data
2.When I enter the new data and try to save it (via sending the Employee Object to an EF Service layer to save changes the Employee object is null and the process fail. How to fix this problem?

Converting my comment to answer as requested :
Simply create a brand new Employee object upon button "New" clicked. That will answer both questions:
It is a better way (if I can't claim it as right way) to clear
controls preparing for entering new data
That can avoid Employee object is null problem when trying to save
And it is logically correct, click "New" button -> create "New" Employee.

Related

WPF & Prism 4.1 Garbage Collection / Memory Issues

I built a Prism application using WPF, .Net 4, Prism 4.1, and Unity. I'm using a DirectoryModuleCatalog to find modules at runtime. My views are displayed in a TabControl (MainRegion). When I remove a view from the region, the view and viewmodel remain in memory and never get garbage collected - the tabitem is removed. After many hours searching, I cannot figure out what I'm doing wrong.
Here's my bootstrapper:
public class Bootstrapper : UnityBootstrapper
{
protected override void InitializeShell()
{
base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
protected override DependencyObject CreateShell()
{
var shell = new Shell();
return shell;
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog() { ModulePath = #".\Modules" };
}
}
Here's my module:
[Module(ModuleName = "ModuleA")]
public class Module : IModule
{
private IRegionManager _regionManager;
public Module(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
var view = new UserControl1();
//_regionManager.RegisterViewWithRegion("MainRegion", typeof(UserControl1));
_regionManager.Regions["MainRegion"].Add(view, "ModuleA");
_regionManager.Regions["MainRegion"].Activate(view);
}
}
And heres the viewmodel for my view that gets added to the region:
public class ViewModel
{
public DelegateCommand RemoveView { get; set; }
public ViewModel()
{
RemoveView = new DelegateCommand(() =>
{
var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
var view = regionManager.Regions["MainRegion"].GetView("ModuleA");
regionManager.Regions["MainRegion"].Deactivate(view);
regionManager.Regions["MainRegion"].Remove(view);
});
}
}
And here's the code behind for the view:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
I've read that it could be because I'm instantiating the view in the module or perhaps the viewmodel in the view? When I use Red Gate Memory Profiler, and remove the view via the DelegateCommand, the view and viewmodel are both flagged as not being able to be garbage collected. Where is the reference that I'm not properly cutting?
Heres the retention graph from Ants: https://docs.google.com/file/d/0B4XjO9pUQxBXbGFHS1luNUtyOTg/edit?usp=sharing
Here's a test solution showing the issue.
Also, I posted the question on CodePlex as well.
It looks like you have a binding reference to it still in your retention graph.
Read and understand the following:
A memory leak may occur when you use data binding in Windows Presentation Foundation
I think it may be your problem, but you didn't show your actual bindings.
Finally found the root cause of my problem....
In our Shell.xaml we were binding IsDefault in one of our buttons to a PasswordBox's IsKeyboardFocused:
<Button Style="{DynamicResource RedSubmitButtonStyle}" IsDefault="{Binding ElementName=passwordBox1, Path=IsKeyboardFocused}" Command="{Binding LoginCommand}" Content="Login" Height="23" HorizontalAlignment="Left" Margin="145,86,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
IsKeyboardFocused, is a dependency property according to MSDN - so should be good on that end.
It was related to the attached property we had on the Password box that allows us to bind to the Password entered. The focus was remaining on that password box even after we hid the ChildWindow (from WPF toolkit extended). So instead of using IsDefault, I added a keydown event to the PasswordBox and if it was Key.Enter, I would change the focused UI control and log the person into the program.
Here's the full contents of our Shell.xaml file
<Grid x:Name="MainGrid" core:SharedResourceDictionary.MergedDictionaries="TabControlThemes;MenuThemes;ButtonThemes;DataGridThemes;TreeViewThemes;ComboBoxThemes;ListBoxThemes;GroupBoxThemes;ToggleSwitchThemes">
<DockPanel>
<ContentControl x:Name="menuContent" DockPanel.Dock="Top" prism:RegionManager.RegionName="MenuRegion" />
<ContentControl DockPanel.Dock="Bottom" prism:RegionManager.RegionName="FooterRegion" />
<ContentControl DockPanel.Dock="Top" prism:RegionManager.RegionName="MainContentRegion" />
</DockPanel>
<StackPanel Orientation="Horizontal" Panel.ZIndex="4" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button Visibility="{Binding IsFullScreenToggleVisible, Converter={StaticResource visConv}}" Command="{Binding ToggleFullScreen}" Height="50" Name="button4" Width="70" HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top">
<Button.Content>
<TextBlock FontSize="12" FontWeight="Bold" TextWrapping="Wrap" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" Text=" Toggle Full Screen" />
</Button.Content>
</Button>
<Button Visibility="{Binding IsAppCloseButtonVisible, Converter={StaticResource visConv}}" Command="{Binding ShutdownApplication}" Height="50" Name="button3" Width="50" HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top">
<Button.Content>
<Image Source="..\Graphics\close.png" Name="image1" />
</Button.Content>
</Button>
</StackPanel>
<xctk:ChildWindow Name="loginChildWindow" Panel.ZIndex="3" CloseButtonVisibility="Collapsed" FocusedElement="{Binding ElementName=usernameTextBox}" WindowStartupLocation="Center" WindowState="{Binding IsVisible, Mode=TwoWay, Converter={StaticResource boolConverter}}" IsModal="True" OverlayOpacity="1" Caption="Pioneer Login" Height="164" Width="261">
<xctk:ChildWindow.OverlayBrush>
<ImageBrush Stretch="None" Viewport="0,0,46,29" ViewportUnits="Absolute" ImageSource="../Graphics/escheresque.png" TileMode="Tile" />
</xctk:ChildWindow.OverlayBrush>
<xctk:BusyIndicator IsBusy="{Binding IsLoginBusy}" BusyContent="Authenticating...">
<Grid>
<TextBox GotFocus="usernameTextBox_GotFocus" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="99,20,0,0" Name="usernameTextBox" VerticalAlignment="Top" Width="120">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding LoginCommand}" />
</TextBox.InputBindings>
</TextBox>
<Label Content="Username" Height="28" HorizontalAlignment="Left" Margin="28,18,0,0" Name="label1" VerticalAlignment="Top" />
<Label Content="Password" Height="28" HorizontalAlignment="Left" Margin="29,47,0,0" Name="label2" VerticalAlignment="Top" />
<PasswordBox attach:PasswordBoxAssistant.BindPassword="True" attach:PasswordBoxAssistant.BoundPassword="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="100,50,0,0" Name="passwordBox1" VerticalAlignment="Top" Width="120" />
<Button Style="{DynamicResource RedSubmitButtonStyle}" IsDefault="{Binding ElementName=passwordBox1, Path=IsKeyboardFocused}" Command="{Binding LoginCommand}" Content="Login" Height="23" HorizontalAlignment="Left" Margin="145,86,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
<Button Style="{DynamicResource RedSubmitButtonStyle}" Command="{Binding LazyLoginCommand}" Visibility="{Binding IsDebugMode, Converter={StaticResource visConv}}" Content="Quick Login" Height="23" HorizontalAlignment="Left" Margin="23,87,0,0" Name="button2" VerticalAlignment="Top" Width="89" />
</Grid>
</xctk:BusyIndicator>
</xctk:ChildWindow>
</Grid>

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.

How to read all textbox values(Map to database fileds) and store them in Database in WPF - MVVM

I am new to WPF and MVVM. After a long invention i got to know how to retrieve data from database and bind it to a itemcontrol/listview/gridview.
But my problem i am not getting how to read bunch of textbox values and store as a new record in database.
Here is my sample code..
View
<ItemsControl ItemsSource="{Binding AllEmployees}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Text="{Binding FirstName}" Margin="4"/>
<TextBox Width="100" Text="{Binding LastName}" Margin="4"/>
<TextBox Width="100" Text="{Binding Age}" Margin="4"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- For new Employee Details -->
<StackPanel>
<TextBox x:Name="FirstName"/>
<TextBox x:Name="LastName"/>
<TextBox x:Name="Age"/>
<Button Content="New" Command="{Binding NewEmployeeCommand}"/>
</StackPanel>
My cs file is
public ObservableCollection<DataAccess.Employee> AllEmployees
{
get;
private set;
}
public EmployeeListViewModel(EmployeeRepository employeeRepository)
{
if (employeeRepository == null)
{
throw new ArgumentNullException("employeeRepository");
}
_employeeRepository = employeeRepository;
this.AllEmployees = new ObservableCollection<DataAccess.Employee>
(_employeeRepository.ListAll());
}
Now how could i store a new employee Firstname, Lastname, Age in database by reading those text boxes..
How to write function for NewEmployeeCommand event to read the textboxes( mapping of textboxes to appropriate datafileds in database) and store the data in database.
Thanks a Lot !
if you're trying to use MVVM just need to:
Create your ViewModel to contain all the properties your View needs
Bind to those properties in Xaml
For example:
public class EmployeeListViewModel
{
public ObservableCollection<Employee> AllEmployees {get;private set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public int? Age {get;set;}
public ICommand NewEmployeeCommand {get;set;}
//You need to connect to this method by using a Delegate/RelayCommand see link below
public void AddNewEmployee()
{
//Add your real code here to actually insert into the db
var result = InsertEmployeeIntoDatabase(FirstName,LastName,Age);
//You probably want to add this new employee to the list now ;)
AllEmployees.Add(result);
//Now you probably want to reset your fields
FirstName = null;
LastName = null;
Age = null;
}
}
Click here for an implementation of a delegate command
And then just edit your xaml like this:
<ItemsControl ItemsSource="{Binding AllEmployees}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Text="{Binding FirstName}" Margin="4"/>
<TextBox Width="100" Text="{Binding LastName}" Margin="4"/>
<TextBox Width="100" Text="{Binding Age}" Margin="4"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- For new Employee Details -->
<StackPanel>
<TextBox Text={Binding FirstName}"/>
<TextBox Text={Binding LastName}"/>
<TextBox Text={Binding Age}"/>
<Button Content="New" Command="{Binding NewEmployeeCommand}"/>
</StackPanel>
You could pass references in the command parameter:
<StackPanel>
<TextBox x:Name="FirstName"/>
<TextBox x:Name="LastName"/>
<Button Content="New" Command="{Binding NewEmployeeCommand}">
<Button.CommandParameter>
<x:Array Type="{x:Type TextBox}">
<x:Reference Name="FirstName"/>
<x:Reference Name="LastName"/>
</x:Array>
</Button.CommandParameter>
</Button>
</StackPanel>
Depending on what kind of event you use you case the parameter and get the values:
TextBox[] textBoxes = e.Parameter as TextBox[]; //RoutedEvent
TextBox[] textBoxes = parameter as TextBox[]; //If the executed handler provides the parameter
string firstName = textBoxes[0].Text;
string lastName = textBoxes[1].Text;
//create entry; store in DB
Via binding:
<Button.CommandParameter>
<local:MyEntry FirstName="{Binding ElementName=FirstName, Path=Text}"
LastName="{Binding ElementName=LastName, Path=Text}"/>
</Button.CommandParameter>
MyEntry entry = parameter as MyEntry;
//store in DB
you dont read the Textbox values. you need a NewEmployeeViewModel and bind the TextBoxes to the properties.
EDIT:
just create a class with INotifyPropertyChanged and the Properties you need.
public class NewEmployee : INotifyPropertyChanged
{
public string FirstName
{
get{return this._firstname;}
set{this._firstname = value;
OnPropertyChanged("FirstName");}
}
//... other properties
}
xaml
<StackPanel DataContext={Binding MyNewEmployeeProperty}>
<TextBox x:Name="FirstName" Text={Binding FirstName}/>
<TextBox x:Name="LastName" Text={Binding LastName}/>
<TextBox x:Name="Age" Text={Binding Age}/>
<Button Content="New" Command="{Binding NewEmployeeCommand}"/>
</StackPanel>
I got the Correct answer.
My New entry form in xmal Should be
<StackPanel>
<TextBox Text={Binding Employee.FirstName}"/>
<TextBox Text={Binding Employee.LastName}"/>
<TextBox Text={Binding Employee.Age}"/>
<Button Content="New" Command="{Binding NewEmployeeCommand}"/>
</StackPanel>
My cs file
public class EmployeeListViewModel : INotifyPropertyChanged
{
Employee _employee;
RelayCommand _addNewEmployee;
EmployeeRepository _employeeRepository;
public Employee Employee
{
get
{
return _employee;
}
set
{
_employee = value;
OnPropertyChanged("Employee");
}
}
public void NewEmployeeCommand()
{
if(_addNewEmployee == null)
{
_addNewEmployee = new RelayCommand( param => NewEmployeeCommandExecute(),
param => NewEmployeeCommandCanExecute
);
}
}
void NewEmployeeCommandExecute()
{
_employeeRepository.Add(Employee);
_employeeRepository.Save();
}
bool NewEmployeeCommandCanExecute
{
get
{
return true;
}
}
}

refresh datagrid on view from viewmodel

I have a datagrid on a view that is bound to a viewmodel. When I initialze the view, the datagrid is populated with data from the viewmodel (ObservableCollection) as it should. However, with I try to do a search against the data, the datagrid does not get refreshed from the viewmodel. When I breakpoint the code in my viewmodel, I can see the results in the ObservableCollection has changed per my search, but somehow that is not getting communicated back to the view. Here is my view and viewmodel (BTW, I am using VS2010 RTM):
namespace Attendance.ViewModels
{
public class EmployeeSelectViewModel : ViewModel, INotifyPropertyChanged
{
#region Entity list and constructor
public EmployeeSelectViewModel()
{
{
Initialize();
}
}
private void Initialize()
{
if (employeeRpository == null)
employeeRpository = new EmployeeRepository();
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
}
private EmployeeRepository employeeRpository;
private ObservableCollection<EmployeeDto> listOfEmployees;
public ObservableCollection<EmployeeDto> ListOfEmployees
{
get { return listOfEmployees; }
set
{
if (listOfEmployees != value)
{
listOfEmployees = value;
NotifyPropertyChanged("ListOfEmployee");
}
}
}
private EmployeeDto selectedEmployee;
public EmployeeDto SelectedEmployee
{
get { return selectedEmployee; }
set
{
if (selectedEmployee != value)
{
selectedEmployee = value;
NotifyPropertyChanged("SelectedEmployee");
}
}
}
#endregion
#region UI control references
/// <summary>
/// search text property
/// </summary>
private string searchText;
public string SearchText
{
get { return searchText; }
set
{
if (searchText != value)
{
searchText = value;
NotifyPropertyChanged("SearchText");
}
}
}
public string Location { get; set; }
#endregion
#region Relay Commands
/// <summary>
/// new command
/// </summary>
private ViewCommand newCommand;
public ViewCommand NewCommand
{
get
{
if (newCommand == null)
newCommand = new ViewCommand(param => this.NewEmployee());
return newCommand;
}
}
private void NewEmployee()
{
NavigationActions.NewEmployeeView();
}
/// <summary>
/// edit command
/// </summary>
private ViewCommand editCommand;
public ViewCommand EditCommand
{
get
{
if (editCommand == null)
{
editCommand = new ViewCommand(param => this.EditEmployee());
}
return editCommand;
}
}
private void EditEmployee()
{
NavigationActions.OpenEmployeeView(SelectedEmployee);
}
/// <summary>
/// save command
/// </summary>
private ViewCommand saveCommand;
public ViewCommand SaveCommand
{
get
{
if (saveCommand == null)
{
saveCommand = new ViewCommand(
param => this.SaveEmployee(),
param => this.CanSaveEmployee
);
}
return saveCommand;
}
}
public void SaveEmployee()
{
employeeRpository.SaveChanges();
}
private bool CanSaveEmployee
{
get { return true; }
}
/// <summary>
/// clear search command
/// </summary>
private ViewCommand clearSearchCommand;
public ViewCommand ClearSearchCommand
{
get
{
if (clearSearchCommand == null)
clearSearchCommand = new ViewCommand(param => this.ClearSearch());
return clearSearchCommand;
}
}
private void ClearSearch()
{
this.SearchText = string.Empty;
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
}
/// <summary>
/// search command
/// </summary>
private ViewCommand searchCommand;
public ViewCommand SearchCommand
{
get
{
if (searchCommand == null)
searchCommand = new ViewCommand(param => this.SearchEmployee());
return searchCommand;
}
}
private void SearchEmployee()
{
if (this.SearchText == string.Empty || this.SearchText == null)
{
NavigationActions.ShowError("Search Employees.", "Please enter your search text ...");
return;
}
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployeesByQuery(SearchText, Location));
}
/// <summary>
/// exit command
/// </summary>
private ViewCommand exitCommand;
public ViewCommand ExitCommand
{
get
{
if (exitCommand == null)
{
exitCommand = new ViewCommand(param => this.ExitWindow());
}
return exitCommand;
}
}
private void ExitWindow()
{
NavigationActions.CloseCurrentView();
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
<Window x:Class="Attendance.Views.EmployeeSelectView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Attendance.ViewModels"
Title="Employee Maintenance" FocusManager.FocusedElement="{Binding ElementName=txtSearchCriteria}"
Height="525" Width="800" WindowStartupLocation="CenterScreen" WindowState="Normal"
WindowStyle="SingleBorderWindow" Icon="Images/gb_icon.png">
<Window.DataContext>
<vm:EmployeeSelectViewModel />
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DataGrid.Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--xml data start-->
<XmlDataProvider x:Key="LocationData" XPath="LocationList/LocationItem" Source="XMLData/Location.xml"/>
<!--xml data end-->
</ResourceDictionary>
</Window.Resources>
<Grid Width="775">
<DockPanel HorizontalAlignment="Left" Width="770">
<!-- TOOLBAR -->
<DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="5">
<ToolBar FontWeight="Bold">
<!-- NEW -->
<Button Name="btnNew" Command="{Binding Path=NewCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Create a new Customer
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Create a new customer in a new Window tab.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/new.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/new.png" Width="22" Height="22" Margin="2"/>
<Label VerticalAlignment="Center">_New</Label>
</StackPanel>
</Button>
<!-- EDIT -->
<Button Name="btnEdit" Command="{Binding Path=EditCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Edit the current record
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Edit the current selected Customer.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/dialog-information.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/edit.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Edit</Label>
</StackPanel>
</Button>
<!-- SEARCH -->
<Separator />
<TextBox Name="txtSearchCriteria"
MinWidth="300" Margin="5"
BorderThickness="1" BorderBrush="LightGray"
FontWeight="Normal" Foreground="Gray" Text="{Binding Path=SearchText}">
</TextBox>
<Button Name="btnSearch" Command="{Binding Path=SearchCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Search
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Search a specific Customer.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/find.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/find.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Find</Label>
</StackPanel>
</Button>
<Button Name="btnClearSearch" Command="{Binding Path=ClearSearchCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Search
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Clear search results.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/find.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Label VerticalAlignment="Center">_Clear Search</Label>
</StackPanel>
</Button>
<!-- EXIT -->
<Separator />
<Button Name="btnExit" Command="{Binding Path=ExitCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Start the application
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Start the main application with the M-V-MV pattern.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/dialog-information.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/exit.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Exit</Label>
</StackPanel>
</Button>
</ToolBar>
</DockPanel>
<!-- LIST -->
<DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="0,0,0,5">
<Label>Location:</Label>
<ComboBox Name="cboLocation" Grid.Column="1" Grid.Row="4"
ItemsSource="{Binding Source={StaticResource LocationData}}"
DisplayMemberPath="location_text" SelectedValuePath="location_value"
SelectedValue="{Binding Path=Location}"
HorizontalAlignment="Left" Width="175" Margin="4" />
</DockPanel>
<DockPanel Margin="5">
<DataGrid ItemsSource="{Binding Path=ListOfEmployees}" AutoGenerateColumns="False" IsReadOnly="True"
Name="dgEmployee" SelectionMode="Single" SelectionUnit="FullRow" CanUserResizeColumns="True"
SelectedItem="{Binding Path=SelectedEmployee}" GridLinesVisibility="Horizontal">
<DataGrid.Columns>
<DataGridTextColumn Header="Employee ID" Width="SizeToCells" MinWidth="125" Binding="{Binding EmployeeID}" />
<DataGridTextColumn Header="First Name" Width="SizeToCells" MinWidth="200" Binding="{Binding FirstName}" />
<DataGridTextColumn Header="Last Name" Width="SizeToCells" MinWidth="200" Binding="{Binding LastName}" />
<DataGridTextColumn Header="Location" Width="SizeToCells" MinWidth="125" Binding="{Binding Location}" />
<DataGridCheckBoxColumn x:Name="Active" Header="Active" Binding="{Binding active}" MinWidth="75" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</DockPanel>
</Grid>
This was my solution:
<DataGrid Name="dgrid" ItemsSource="{Binding UserSettings, IsAsync=True}" AutoGenerateColumns="False">
The key being the setting of IsAsync=True, allows the screen paint to occur
I found 2 ways to refresh DataGrid:
One was posted by VariableLost, it works with INotifyPropertyChanged but have one drawback. Whole DataGrid is refreshed with blink effect (disappears for a split second). Doesn't look natural.
Other solution is to refresh ObservableCollection in ViewModel or Code Behind (if you're not using MVVM):
CollectionViewSource.GetDefaultView(collectionName).Refresh();
Looks more natural because only changes cells affected by edition.
Your previous code should have also worked, but 'magic strings' got in the way.
Property name is ListOfEmployees and in its setter you raise PropertyChanged event with property name ListOfEmployee. 's' is missing.
Beware of your new code. It will raise CollectionChanged event on ListOfEmployees for every insertion, and that might make your app slower if you are doing many insertions.
For many insertions, it would be better to derive from ObservableCollection and implement Reset method that clears underlying Items, adds new items and raises CollectionChanged event of type Reset.
My question was answered in a post on another site. Instead of creating a new instance of the ListOfEmployees in my view model, I just cleared the existing one and added the results from my repository:
private void SearchEmployee()
{
if (String.IsNullOrEmpty(this.SearchText) || String.IsNullOrEmpty(this.Location))
{
NavigationActions.ShowError("Search Employees.", "Please enter your search text and select a location...");
return;
}
// clear the list and repopulate based on the search criteria
if (ListOfEmployees != null)
{
ListOfEmployees.Clear();
IList<EmployeeDto> iList = employeeRpository.GetEmployeesByQuery(SearchText, Location, IsActive);
foreach (EmployeeDto value in iList)
ListOfEmployees.Add(value);
}
}
That did the trick.

Resources