I'm new to c# and trying to understand how commands work in mvvm architecture. What I need to do is that updating some info when I click a button. I think I implemented the relay class fine but there is no update at all.
RelayCommand.cs
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
MovieViewModel.cs
class MovieViewModel : INotifyPropertyChanged
{
Movie _movie;
private ICommand _updateCommand;
public event PropertyChangedEventHandler PropertyChanged;
public MovieViewModel()
{
_movie = new Movie
{
Title = "Unknown",
Genre = "Unknown",
Price = 11.0,
Score = 0
};
}
public Movie Movie
{
get
{
return _movie;
}
set
{
_movie = value;
}
}
public string Title
{
get
{
return Movie.Title;
}
set
{
Movie.Title = value;
RaisePropertyChanged("Title");
}
}
public string Genre
{
get
{
return Movie.Genre;
}
set
{
Movie.Genre = value;
RaisePropertyChanged("Genre");
}
}
public double Price
{
get
{
return Movie.Price;
}
set
{
Movie.Price = value;
RaisePropertyChanged("Price");
}
}
public double Score
{
get
{
return Movie.Score;
}
set
{
Movie.Score = value;
RaisePropertyChanged("Score");
}
}
private void RaisePropertyChanged(string name)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public ICommand UpdateCommand
{
get
{
if (_updateCommand == null)
{
_updateCommand = new RelayCommand(p => { updateMovie("ASD", "ZXC", 11.90, 0); }, p => true);
}
return _updateCommand;
}
set
{
_updateCommand = value;
}
}
public Movie updateMovie(string title, string genre, double price, double score)
{
_movie.Title = title;
_movie.Genre = genre;
_movie.Price = price;
_movie.Score = score;
return _movie;
}
}
Button command binding
<Button x:Name="updateBtn" Content="Update" Grid.Column="1" Grid.Row="5" Width="75" Height="30" Command="{Binding UpdateCommand}"/>
Try giving
RaisePropertyChanged("Movie");
Thanks #Maverik has given the reason statement too. You're not raising PropertyChanged event since you bypass the property and access the underlying fields directly. You should use the VM like it's meant to.
The access going through VM to model applies to you just as much as it applies to views and other bound clients to your VM.
Related
I'm new to Xamarin Forms, I am trying to get/Pass the Id value from XAML UI to my ViewModel
My XAML:
TODO
My VM:
private int id;
public int Id
{
get
{
return id;
}
set
{
if (id != value)
{
id = value;
OnPropertyChanged("Id");
}
}
}
public string result { get; set; }
public ICommand SubmitResultsCommand
{
get
{
return new Command(async () =>
{
IsLoading = true;
Result _result = new Result();
var response
= await _services.SubmitResultsAsync(result, id, Settings.AccessToken);
IsLoading = false;
});
}
}
in ViewModel
Define the binding property which you need to bind to view in xaml
public class MyViewModel: INotifyPropertyChanged
{
// it is necessary if you want to change the value of Id in runtime
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string id;
public string Id
{
get
{
return id;
}
set
{
if (id != value)
{
id = value;
NotifyPropertyChanged("Id");
}
}
}
// other properties
}
In ContentPage
Set the BindingContext
public MainPage()
{
InitializeComponent();
BindingContext = new MyViewModel();
}
I have problem with my application, especially with Bindings in WPF MVVM.
I created Model, ViewModel and View, this is part of my code (only this connected with my problem) When I click the button nemed : PointUp i want to see the amount of Team1 points. Can anyone tell me what i'm doing wrong?
View
<Window x:Class="Tabu.Game
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:Tabu"
xmlns:vm="clr-namespace:Tabu.ViewModel"
mc:Ignorable="d"
Title="Game" Height="600" Width="900" Background="Beige">
<Window.DataContext>
<vm:TeamStatistic />
</Window.DataContext>
<Grid>
<Button x:Name="PointUp" Command="{Binding AddPoints }" Content="+"/>
<Label x:Name="PointsTeam1_label" Content="{Binding Team1.TeamPoints, UpdateSourceTrigger=PropertyChanged }"/>
</Grid>
Model
'namespace Tabu.Model
{
public class Team
{
public bool IsTeamActive { get; set; }
public int TeamMiss { get; set; }
public int TeamPoints { get; set; }
public int TeamMistake { get; set; }
}
}'
ViewModel
namespace Tabu.ViewModel
{
class TeamStatistic : INotifyPropertyChanged
{
public Team Team1 = new Team();
public int TeamPoints
{
get { return TeamPoints; }
set { TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
public ICommand AddPoints
{
get { return new RelayCommand(() => Add_Points()); }
}
public void Add_Points()
{
Team1.TeamPoints++;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(params string[] propsName)
{
if (PropertyChanged!=null)
{
foreach(string propName in propsName)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class RelayCommand : ICommand
{
private readonly Func<bool> canExecute;
private readonly Action execute;
public RelayCommand(Action execute)
: this(execute, null) { }
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { if (this.canExecute != null) CommandManager.RequerySuggested += value; }
remove { if (this.canExecute != null) CommandManager.RequerySuggested -= value; }
}
public Boolean CanExecute(object parameter) { return this.canExecute == null ? true : this.canExecute(); }
public void Execute(object parameter) { this.execute(); }
}
}
The problem is here:
public int TeamPoints
{
get { return TeamPoints; } //should be Team1.TeamPoints
set { TeamPoints = value; OnPropertyChanged("TeamPoints"); } //should be Team1.TeamPoints
}
Inside your TeamPoints property in ViewModel you return and set the same property TeamPoints from ViewModel but you should set from Model (Team1). You should return and set Team1.TeamPoints.
public int TeamPoints
{
get { return Team1.TeamPoints; }
set { Team1.TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
And Add_Points():
public void Add_Points()
{
Team1.TeamPoints++;
OnPropertyChanged("TeamPoints");
}
You have to update your Binding like this.
<Label x:Name="PointsTeam1_label" Content="{Binding TeamPoints, UpdateSourceTrigger=PropertyChanged }"/>
When you bind to Team1.TeamPoints you will not get the Notification from OnPropertyChanged which is inside your TeamPoints property.
I reckon it is because of AddPoints (the command binding). Since this command is binded & you are creating an instance of RelayCommand & returning each time it might be breaking the binding.
A better alternative with CommandBindings are to declare the property and initialize them in the Constructor of the view model.
Ex:
namespace Tabu.ViewModel
{
class TeamStatistic : INotifyPropertyChanged
{
public Team Team1 = new Team();
public int TeamPoints
{
get { return Team1.TeamPoints; }
set { Team1.TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
private ICommand _AddPoints;
public ICommand AddPoints
{
get { return _AddPoints; }
set { _AddPoints = value; }
}
public void Add_Points()
{
Team1.TeamPoints++;
}
public TeamStatistic ()
{
_AddPoinss = new RelayCommand(Add_Points);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(params string[] propsName)
{
if (PropertyChanged!=null)
{
foreach(string propName in propsName)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
I'm using MVVM with WPF and have a RadComboBox in my view that needs to be populated from my County table in my database. My viewmodel is as follows:
public class AddClientViewModel : BindableBase
{
private Client _client;
private Circuit _circuit;
private County _county;
private State _state;
private SubscriberSpecialty _subscriberSpecialty;
private IClientsRepository _repository = new ClientRepository();
private ICircuitRepository _circuitRepository = new CircuitRepository();
private ICountyRepository _countyRepository = new CountyRepository();
private IStateRepository _stateRepository = new StateRepository();
private ISubscriberSpecialty _subscriberSpecialtyRepository = new SubscriberSpecialtyRepository();
public AddClientViewModel()
{
SaveCommand = new RelayCommand(OnSave);
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public Client Client
{
get { return _client; }
set
{
if (value != _client)
{
_client = value;
PropertyChanged(this, new PropertyChangedEventArgs("Client"));
}
}
}
public Circuit Circuit
{
get { return _circuit; }
set
{
if(value != _circuit)
{
_circuit = value;
PropertyChanged(this, new PropertyChangedEventArgs("Circuit"));
}
}
}
public County County
{
get { return _county;}
set
{
if (value != _county)
{
_county = value;
PropertyChanged(this, new PropertyChangedEventArgs("County"));
}
}
}
public State State
{
get { return _state; }
set
{
if (value != _state)
{
_state = value;
PropertyChanged(this, new PropertyChangedEventArgs("State"));
}
}
}
public SubscriberSpecialty SubscriberSpecialty
{
get { return _subscriberSpecialty; }
set
{
if (value != _subscriberSpecialty)
{
_subscriberSpecialty = value;
PropertyChanged(this, new PropertyChangedEventArgs("SubscriberSpecialty"));
}
}
}
public Guid ClientId { get; set; }
public Guid CircuitId { get; set; }
public Guid CountyId { get; set; }
public Guid StateId { get; set; }
public Guid SubscriberSpecialtyId { get; set; }
public ICommand SaveCommand { get; set; }
public event Action<Client> AddClient = delegate { };
public async void LoadClient()
{
Client = await _repository.GetClientAsync(ClientId);
}
public async void LoadCircuit()
{
Circuit = await _circuitRepository.GetCircuitAsync(CircuitId);
}
public async void LoadCounty()
{
County = await _countyRepository.GetCountyAsync(CountyId);
}
public async void LoadState()
{
State = await _stateRepository.GetStateAsync(StateId);
}
public async void LoadSubscriberSpecialty()
{
SubscriberSpecialty = await _subscriberSpecialtyRepository.GetSubscriberSpecialtyAsync(SubscriberSpecialtyId);
}
private void OnAddClient()
{
AddClient(new Client {ClientId = Guid.NewGuid()});
}
private async void OnSave()
{
try
{
Client = await _repository.AddClientAsync(new Client());
}
catch (Exception ex)
{
MessageBox.Show("A handled exception just occurred: " + ex.Message, "Exception", MessageBoxButton.OK,
MessageBoxImage.Warning);
}
}
}
The interface has the following:
Task<County> GetCountyAsync(Guid countyId);
The repository class calls the interface as:
public Task<List<County>> GetCountiesAsync()
{
return _context.Counties.ToListAsync();
}
My view then uses the following syntax:
<telerik:RadComboBox x:Name="Countycombo"
Grid.Column="1" Grid.Row="3"
ItemsSource="{Binding County.CountyName}"
DisplayMemberPath="CountyName" Width="120"/>
I defined a DataContext in the layout as follows:
<UserControl.DataContext>
<viewModels:AddClientViewModel />
</UserControl.DataContext>
When I run the application, the RadComboBox doesn't grab the values from the County table, into which I've loaded several values for CountyName. How do I correct the above code snippets to ensure my County Names are populated?
Update: When I remove County from County.CountyName, I receive the message stating Cannot resolve property CountyName in DataContext MySolution.ViewModels.MyViewModel What additional work is needed in the viewmodel either in LoadCounty or other sections?
I would suggest the following:
Introduce the ViewModel property that will hold a list of County objects:
private List<County> _counties;
public List<County> Counties
{
get { return _counties;}
set
{
if (value != _counties)
{
_counties = value;
PropertyChanged(this, new PropertyChangedEventArgs("Counties"));
}
}
}
Bind a ComboBox ItemsSource to the Counties property, and a ComboBox SelectedItem property to the County property.
<telerik:RadComboBox x:Name="Countycombo"
Grid.Column="1" Grid.Row="3"
ItemsSource="{Binding Counties}"
SelectedItem="{Binding County}"
DisplayMemberPath="CountyName" Width="120"/>
And you need to a place where you will load the counties with a repository call to a GetCountiesAsync. The result should be set to the ViewModel Counties property.
public async void LoadCounties()
{
Counties = await _countyRepository.GetCountiesAsync();
}
Not sure what is the best place to make that call.
XAML Button:
<Button Content="Test Connection" Name="btnTestConnection" Command="{Binding Path=TestCommand}" CommandParameter="{Binding ElementName=someObject}"/>
View Model:
public ICommand TestCommand
{
get;
internal set;
}
private bool CanExecuteTestCommand()
{
return !String.IsNullOrEmpty(txtControl);
}
private void CreateTestCommand()
{
TestCommand = new TestCommand(TestExecute);
}
public void TestExecute(object parameter)
{
//do stuff with parameter
obj.TestConnection(parameter);
}
I would like to point out that CreateTestCommand() is called in my VM constructor.
And finally, my implementation of TestCommand:
class TestCommand : ICommand
{
private Action<object> execute;
private Predicate<object> canExecute;
private event EventHandler CanExecuteChangedInternal;
public TestCommand(Action<object> execute)
: this(execute, DefaultCanExecute)
{
}
public TestCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
if (canExecute == null)
{
throw new ArgumentNullException("canExecute");
}
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
this.CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
this.CanExecuteChangedInternal -= value;
}
}
public bool CanExecute(object parameter)
{
return this.canExecute != null && this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public void OnCanExecuteChanged()
{
EventHandler handler = this.CanExecuteChangedInternal;
if (handler != null)
{
handler.Invoke(this, EventArgs.Empty);
}
}
public void Destroy()
{
this.canExecute = _ => false;
this.execute = _ => { return; };
}
private static bool DefaultCanExecute(object parameter)
{
return true;
}
}
I set a breakpoint in CreateTestCommand and it looks like it's configured properly:
But when I click on btnTestConnection, nothing happens. TestExecute in my View Model isn't called (which calls TestConnection on the actual model). I must be missing something, but I can't for the life of me figure out what...
EDIT Including the rest of my view model;
class FormProcessorViewModel
{
FormProcessorModel obj;
public FormProcessorViewModel()
{
obj = new FormProcessorModel();
CreateTestCommand();
}
public FormProcessorViewModel(string server, string database, string username, bool specifyDateRange, DateTime startDate, DateTime endDate, string operation, string preprocessed, string processed, string failed) :this()
{
txtServer = server;
txtDatabase = database;
txtUsername = username;
chkSpecifyDateRange = specifyDateRange;
dpStartDate = startDate;
dpEndDate = endDate;
txtOperation = operation;
txtPreprocessed = preprocessed;
txtProcessed = processed;
txtFailed = failed;
}
public ICommand TestCmd
{
get;
internal set;
}
private bool CanExecuteTestCommand()
{
return !String.IsNullOrEmpty(txtUsername);
}
private void CreateTestCommand()
{
TestCmd = new TestCommand(TestExecute);
}
private void TestExecute(object parameter)
{
var passwordBox = parameter as PasswordBox;
var password = passwordBox.Password;
obj.TestConnection(password);
}
}
I left out all the properties that get set in the second constructor just because they don't really do anything but refer to the corresponding values on the model object.
EDIT
View Model
class ViewModel : INotifyPropertyChanged
{
private string _test;
public string TestValue
{
get { return _test; }
set { _test = value; RaisePropertyChanged("TestValue"); }
}
public ICommand MyCommand { get; internal set; }
public ViewModel()
{
TestValue = "Test";
CreateTestCommand();
}
private void CreateTestCommand()
{
MyCommand = new TestCommand(ExecuteButton);
}
private void ExecuteButton(object obj)
{
TestValue = "Cool";
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string propName)
{
var pc = PropertyChanged;
if (pc != null)
{
pc(this, new PropertyChangedEventArgs(propName));
}
}
}
Xaml
<Button Content="{Binding TestValue}" Command="{Binding Path=MyCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
Xaml Code behind.
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
Update
Managed to fix the selectedIndex problem. I'd forgotten to set SelectedItem as well and naturally that caused a few issues.
So at 9AM this morning we got our 24 hour assignment and I have hit a brick wall.
We're supposed to create a program that allows a supervisor to Add and delete Employees and add Working Sessions, total hours and total earnings. But I am having some problems succesfully implementing this following the MVVM-Pattern. For some reason my Bindings simply aren't working and the only Solution I can see is someone looking over my project and helping me troubleshoot it.
Here is my code - I'm very sorry about having to post the entire thing but given that I have no clue where the problem is I did not see any other options. :
EmployeeModel
[Serializable]
public class WorkSessions : ObservableCollection<WorkSessionModel>
{
public WorkSessions()
{
}
}
[Serializable]
public class WorkSessionModel : INotifyPropertyChanged
{
private DateTime _dateTime;
private string _id;
private double _hours;
public WorkSessionModel()
{
}
public DateTime DateTime
{
get { return _dateTime; }
set
{
_dateTime = value;
NotifyPropertyChanged("DateTime");
}
}
public string ID
{
get { return _id; }
set
{
_id = value;
NotifyPropertyChanged("ID");
}
}
public double Hours
{
get { return _hours; }
set
{
_hours = value;
NotifyPropertyChanged("Hours");
NotifyPropertyChanged("TotalHours");
}
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
WorkSessionModel
[Serializable]
public class WorkSessions : ObservableCollection<WorkSessionModel>
{
public WorkSessions()
{
}
}
[Serializable]
public class WorkSessionModel : INotifyPropertyChanged
{
private DateTime _dateTime;
private string _id;
private double _hours;
public WorkSessionModel()
{
}
public DateTime DateTime
{
get { return _dateTime; }
set
{
_dateTime = value;
NotifyPropertyChanged("DateTime");
}
}
public string ID
{
get { return _id; }
set
{
_id = value;
NotifyPropertyChanged("ID");
}
}
public double Hours
{
get { return _hours; }
set
{
_hours = value;
NotifyPropertyChanged("Hours");
NotifyPropertyChanged("TotalHours");
}
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
EmployeeViewModel
public class EmployeeViewModel : ViewModelBase
{
private Employees _employeesModel = new Employees();
public Employees EmployeesView = new Employees();
public ObservableCollection<WorkSessionModel> WorkSessions { get; set; }
private string _id = "0";
private string _name = "noname";
private double _wage = 0;
private int _totalhours = 0;
public string ID
{
get { return _id; }
set { _id = value; RaisePropertyChanged("ID"); }
}
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
public double Wage
{
get { return _wage; }
set
{
_wage = value;
RaisePropertyChanged("Wage");
}
}
public int TotalHours
{
get { return _totalhours; }
set
{
_totalhours = value;
RaisePropertyChanged("TotalHours");
}
}
private EmployeeModel _selectedEmployee = new EmployeeModel();
public EmployeeModel SelectedEmployee
{
get { return _selectedEmployee; }
set
{
_selectedEmployee = value;
RaisePropertyChanged("SelectedEmployee");
}
}
private int _selectedEmployeeIndex;
public int SelectedEmployeeIndex
{
get { return _selectedEmployeeIndex; }
set
{
_selectedEmployeeIndex = value;
RaisePropertyChanged("SelectedEmployeeIndex");
}
}
#region RelayCommands
// Employee Relay Commands
public RelayCommand EmployeeAddNewCommand { set; get; }
public RelayCommand EmployeeDeleteCommand { set; get; }
public RelayCommand EmployeeNextCommand { set; get; }
public RelayCommand EmployeePrevCommand { set; get; }
public RelayCommand EmployeeTotalHoursCommand { get; set; }
#endregion
public EmployeeViewModel()
{
InitCommands();
}
private void InitCommands()
{
EmployeeAddNewCommand = new RelayCommand(EmployeeAddNewExecute, EmployeeAddNewCanExecute);
EmployeeDeleteCommand = new RelayCommand(EmployeeDeleteNewExecute, EmployeeDeleteCanExecute);
EmployeeNextCommand = new RelayCommand(EmployeeNextExecute, EmployeeNextCanExecute);
EmployeePrevCommand = new RelayCommand(EmployeePrevExecute, EmployeePrevCanExecute);
//EmployeeTotalHoursCommand = new RelayCommand(EmployeeTotalHoursExecute, EmployeeTotalHoursCanExecute);
}
//private void EmployeeTotalHoursExecute()
//{
// _selectedEmployee.TotalHours();
//}
//private bool EmployeeTotalHoursCanExecute()
//{
// return true;
//}
private void EmployeeAddNewExecute()
{
EmployeeModel newEmployee = new EmployeeModel();
EmployeesView.Add(newEmployee);
_employeesModel.Add(newEmployee);
SelectedEmployee = newEmployee;
}
private bool EmployeeAddNewCanExecute()
{
return true;
}
private void EmployeeDeleteNewExecute()
{
if (MessageBox.Show("You are about delete all submissions for Employee," + SelectedEmployee.Name + "(" + SelectedEmployee.ID +")\r\nAre you sure?", "This is a Warning!", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
_employeesModel.Remove(SelectedEmployee);
EmployeesView.Remove(SelectedEmployee);
}
}
private bool EmployeeDeleteCanExecute()
{
if (SelectedEmployee != null)
return true;
else return false;
}
private void EmployeeNextExecute()
{
SelectedEmployeeIndex++;
}
private bool EmployeeNextCanExecute()
{
if (SelectedEmployeeIndex < EmployeesView.Count - 1)
return true;
return false;
}
private void EmployeePrevExecute()
{
SelectedEmployeeIndex--;
}
private bool EmployeePrevCanExecute()
{
if (SelectedEmployeeIndex > 0)
return true;
return false;
}
}
View
public partial class MainWindow : Window
{
public EmployeeViewModel EmployeeViewModel = new EmployeeViewModel();
public MainWindow()
{
InitializeComponent();
menu_employee.DataContext = EmployeeViewModel;
sp_employees.DataContext = EmployeeViewModel;
datagrid_employees.ItemsSource = EmployeeViewModel.EmployeesView;
grid_selectedEmployee.DataContext = EmployeeViewModel.SelectedEmployee;
}
}
I can see a few problems with your code:
When the SelectedIndex is updated, SelectedItem remains the same and vice versa.
It looks like your data binding is out of order:
The DataContext property cascades down to every child of a certain dependency object.
The code in the MainWindow constructor should probably be replaced by:
this.DataContext = EmployeeViewModel;
Then in XAML set the rest of the properties using Data Binding. The problem in your situation is that the DataContext of the selectedemployee is only set once. This means if you select another employee, then it will not update.
An example for your SelectedEmployee grid:
<Grid Name="grid_selectedEmployee" DataContext="{Binding SelectedEmployee,
UpdateSourceTrigger=PropertyChanged}">...</Grid>
One of the biggest things I see is you are setting properties, not binding them.
For example,
datagrid_employees.ItemsSource = EmployeeViewModel.EmployeesView;
You are telling your DataGrid that it's ItemsSource should be that specific object. You need to bind it to that value so you are telling it to point to that property instead. This will make your UI correctly reflect what's in your ViewModel
The other huge red flag I see is your ViewModel referencing something called and EmployeeView which leads me to believe your View and ViewModel too closely tied together.
Your ViewModel should contain all your business logic and code, while the View is usually XAML and simply reflects the ViewModel in a user-friendly way.
The View and the ViewModel should never directly reference each other (I have had my View reference my ViewModel in some rare occasions, but never the other way around)
For example, an EmployeesViewModel might contain
ObservableCollection<Employee> Employees
Employee SelectedEmployee
ICommand AddEmployeeCommand
ICommand DeleteEmployeeCommand
while your View (XAML) might look like this:
<StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="Add" Command="{Binding AddEmployeeCommand}" />
<Button Content="Delete" Command="{Binding DeleteEmployeeCommand}" />
</StackPanel>
<DataGrid ItemsSource="{Binding Employees}"
SelectedItem="{Binding SelectedEmployee}">
... etc
</DataGrid>
<UniformGrid DataContext="{Binding SelectedEmployee}" Columns="2" Rows="4">
<TextBlock Text="ID" />
<TextBox Text="{Binding Id}" />
... etc
</UniformGrid >
</StackPanel>
And the only thing you should be setting is the DataContext of the entire Window. Usually I overwrite App.OnStartup() to start up my application:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var view = new MainWindow();
var vm = new EmployeesViewModel;
view.DataContext = vm;
view.Show();
}
}
Although I suppose in your case this would also work:
public MainWindow()
{
InitializeComponent();
this.DataContext = new EmployeesViewModel();
}