Xamarin Forms Binding not showing on ListView - c#

I'm new to Xamarin and I'm trying to bind my ViewModel to the View but I couldn't do it yet.
Here's the code.
(Model)
namespace CadastroProdutos
{
public class Produto
{
public string Codigo { get; set; }
public string Identificacao { get; set; }
public string Tipo { get; set; }
}
}
(Observable Model)
namespace CadastroProdutos
{
public class ObservableProduto : INotifyPropertyChanged
{
Produto produto;
public ObservableProduto()
{
produto = new Produto()
{
Identificacao = "Primeiro",
Codigo = "123456"
};
produto = new Produto()
{
Identificacao = "Segundo",
Codigo = "123456"
};
produto = new Produto()
{
Identificacao = "Terceiro",
Codigo = "123456"
};
}
public event PropertyChangedEventHandler PropertyChanged;
public string Codigo
{
set
{
if (!value.Equals(produto.Codigo, StringComparison.Ordinal))
{
produto.Codigo = value;
OnPropertyChanged("Codigo");
}
}
get
{
return produto.Codigo;
}
}
public string Identificacao
{
set
{
if (!value.Equals(produto.Identificacao, StringComparison.Ordinal))
{
produto.Identificacao = value;
OnPropertyChanged("Identificacao");
}
}
get
{
return produto.Identificacao;
}
}
public string Tipo
{
set
{
if (!value.Equals(produto.Tipo, StringComparison.Ordinal))
{
produto.Tipo = value;
OnPropertyChanged("Tipo");
}
}
get
{
return produto.Tipo;
}
}
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler == null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
(ViewModel)
namespace CadastroProdutos
{
public class ListProdutoViewModel
{
ObservableCollection<ObservableProduto> produtos;
public ListProdutoViewModel()
{
produtos = new ObservableCollection<ObservableProduto>();
}
public ObservableCollection<ObservableProduto> Produtos
{
set
{
if (value != produtos)
{
produtos = value;
}
}
get
{
return produtos;
}
}
}
}
(View)
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:CadastroProdutos;"
x:Class="CadastroProdutos.ListProduto"
Title="Listagem de Produtos">
<ContentPage.Content>
<ListView x:Name="listView" Margin="20,40,20,20" ItemsSource="{Binding Produtos}">
<ListView.BindingContext>
<local:ListProdutoViewModel />
</ListView.BindingContext>
<ListView.Header>
<StackLayout Orientation="Vertical" >
<Label Text="Produtos" HorizontalOptions="Center"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" >
<TextCell Text="{Binding Identificacao}"/>
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
It not worked, It didn't show those elements on the list. Can someone help me?
Thanks in advance.

You're not quite understanding the MVVM approach, but you're almost there. You don't need to have the ObservableProduto class. You can make your Produto class your model.
This is your Produto model. I went ahead and changed it up for you.
namespace CadastroProdutos
{
public class Produto : INotifyPropertyChanged
{
private string codigo;
public string Codigo
{
get {return codigo;}
set {codigo=value; OnPropertyChanged(); }
}
private string identificacao;
public string Identificacao
{
get {return identificacao;}
set {identificacao=value; OnPropertyChanged(); }
}
private string tipo ;
public string Tipo
{
get {return tipo;}
set {tipo=value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName]string propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
You should contain an ObservableCollection of your Produtos in a viewmodel. I see you've done that. I've edited it a bit. You may need to be careful about totally resetting your ObservableCollection on a set.
namespace CadastroProdutos
{
public class ListProdutoViewModel
{
ObservableCollection<Produto> produtos;
public ListProdutoViewModel()
{
produtos = new ObservableCollection<Produto>();
}
public ObservableCollection<Produto> Produtos
{
set
{
if (value != produtos)
{
produtos = value;
}
}
get
{
return produtos;
}
}
}
}
Note: you will need to add items to your ObservableColleciton still.

Related

CollectinView Grouping doesnt show all Items in the last Group

im working on an Mobile App for Android in Xamarin Forms, and have one problem. I have a ObservableCollection that i fill with the following Model.
private int _category_ID;
public int Category_ID
{
get
{
return _category_ID;
}
set
{
_category_ID = value;
OnPropertyChanged("_category_ID");
}
}
private string _category_Name;
public string Category_Name
{
get
{
return _category_Name;
}
set
{
_category_Name = value;
OnPropertyChanged("_category_Name");
}
}
private string _category_Description;
public string Category_Description
{
get
{
return _category_Description;
}
set
{
_category_Description = value;
OnPropertyChanged("_category_Description");
}
}
public CategoryModel(string name, List<ProductModel> products) : base(products)
{
Category_Name = name;
}
That works fine and all Categorys and Items shows right when i Debugging in the ObservableCollection. Example: Categroy 1 = 2 Items Category 2 = 3 Items Category 3 = 4 Items.
That works.
But my problem is, that when i use a CollectionView like this
<CollectionView ItemsSource="{Binding ObservCollectionCategory}" IsGrouped="True">
<CollectionView.ItemTemplate>
<DataTemplate>
<ScrollView>
<Grid Padding="10">
<StackLayout BackgroundColor="Blue">
<Label Text="{Binding Product_Name}"/>
<Label Text="{Binding Product_Description}"/>
</StackLayout>
</Grid>
</ScrollView>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.GroupHeaderTemplate>
<DataTemplate >
<Label Text="{Binding Category_Name}"/>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</CollectionView>
The View shows me only the first item of the last categroy and the other ignores. All other Categorys shows right.
When i create a blank Categroy at the end of the ObservableCollection then all Items, from the last category, shows in the View. But i have an empty Group then at the end.
I have try to show me the count in the header, and the count the right one (4).
You could try the code below.
Model:
public class ProductModel : INotifyPropertyChanged
{
private string _product_Name;
public string Product_Name
{
get
{
return _product_Name;
}
set
{
_product_Name = value;
OnPropertyChanged("Product_Name");
}
}
private string _product_Description;
public string Product_Description
{
get
{
return _product_Description;
}
set
{
_product_Description = value;
OnPropertyChanged("Product_Description");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class CategoryModel : List<ProductModel>, INotifyPropertyChanged
{
private string _category_Name;
public event PropertyChangedEventHandler PropertyChanged;
public string Category_Name
{
get
{
return _category_Name;
}
set
{
_category_Name = value;
OnPropertyChanged("Category_Name");
}
}
public CategoryModel(string name, List<ProductModel> diary) : base(diary)
{
Category_Name = name;
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Code behind:
public ObservableCollection<CategoryModel> ObservCollectionCategory { get; set; } = new ObservableCollection<CategoryModel>();
public Page18()
{
InitializeComponent();
ObservCollectionCategory.Add(new CategoryModel("Categroy 1", new List<ProductModel>
{
new ProductModel(){ Product_Name="item1", Product_Description="Description1"},
new ProductModel(){ Product_Name="item2", Product_Description="Description2"},
}));
ObservCollectionCategory.Add(new CategoryModel("Categroy 2", new List<ProductModel>
{
new ProductModel(){ Product_Name="item1", Product_Description="Description1"},
new ProductModel(){ Product_Name="item2", Product_Description="Description2"},
new ProductModel(){ Product_Name="item3", Product_Description="Description3"},
}));
ObservCollectionCategory.Add(new CategoryModel("Categroy 3", new List<ProductModel>
{
new ProductModel(){ Product_Name="item1", Product_Description="Description1"},
new ProductModel(){ Product_Name="item2", Product_Description="Description2"},
new ProductModel(){ Product_Name="item3", Product_Description="Description3"},
new ProductModel(){ Product_Name="item4", Product_Description="Description4"},
}));
this.BindingContext = this;
}
Output:

Xamarin Forms Binding with namespace declaration error

I'm new to Xamarin and I'm trying to bind my ViewModel to the View but I couldn't do it yet.
Here's the code.
(Model)
namespace CadastroProdutos
{
public class Produto
{
public string Codigo { get; set; }
public string Identificacao { get; set; }
public string Tipo { get; set; }
}
}
(Observable Model)
namespace CadastroProdutos
{
public class ObservableProduto : INotifyPropertyChanged
{
Produto produto;
public ObservableProduto()
{
}
public event PropertyChangedEventHandler PropertyChanged;
public string Codigo
{
set
{
if (!value.Equals(produto.Codigo, StringComparison.Ordinal))
{
produto.Codigo = value;
OnPropertyChanged("Codigo");
}
}
get
{
return produto.Codigo;
}
}
public string Identificacao
{
set
{
if (!value.Equals(produto.Identificacao, StringComparison.Ordinal))
{
produto.Identificacao = value;
OnPropertyChanged("Identificacao");
}
}
get
{
return produto.Identificacao;
}
}
public string Tipo
{
set
{
if (!value.Equals(produto.Tipo, StringComparison.Ordinal))
{
produto.Tipo = value;
OnPropertyChanged("Tipo");
}
}
get
{
return produto.Tipo;
}
}
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler == null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
(ViewModel)
namespace CadastroProdutos
{
public class ListProdutoViewModel
{
ObservableCollection<ObservableProduto> produtos;
public ListProdutoViewModel()
{
produtos = new ObservableCollection<ObservableProduto>();
}
public ObservableCollection<ObservableProduto> Produtos
{
set
{
if (value != produtos)
{
produtos = value;
}
}
get
{
return produtos;
}
}
}
}
(View)
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:CadastroProdutos;assembly=CadastroProdutos"
x:Class="CadastroProdutos.ListProduto"
Title="Listagem de Produtos">
<ContentPage.Content>
<ListView x:Name="listView" Margin="20,40,20,20" ItemsSource="{Binding Produtos}">
<ListView.BindingContext>
<local:ListProdutoViewModel />
</ListView.BindingContext>
<ListView.Header>
<StackLayout Orientation="Vertical" >
<Label Text="Produtos" HorizontalOptions="Center"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" >
<TextCell Text="{Binding Identificacao}"/>
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
Getting an error "Xamarin.Forms.Xaml.XamlParseException Position 10:6. Type local:ListProdutoViewModel not found in xmlns clr-namespace:CadastroProdutos;assembly=CadastroProdutos".
What am I missing on the namespace declaration?
Thanks in advance.
Ensure that whether ListProdutoViewModel is deifined under the namespace - CadastroProdutos.
Also, you no need to mention the assembly there in, local: assembly=CadastroProdutos. So try to run the application after removing the above assembly code. Like as below,
local="clr-namespace:CadastroProdutos"

Property changed event is not getting fired wpf

I have to change the value in a text box dynamically, on selecting a value from a combox box, which is present in different view. when changing the dependency property's source, the propertychangedEventHandler value is not changing, i.e it is remaining as null, so the event is not getting fired. As a result the text in the textbox is not changing. Below is the code. I have bound the text in textbox to _name property.
public partial class Details : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string name = "";
public Details()
{
InitializeComponent();
Name = Connector.Name;
DataContext = this;
}
public string Name
{
get { return name; }
set
{
name = value; OnPropertyChanged("Name");
}
}
protected void OnPropertyChanged(string s)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(s));
}
}
}
Xaml code
<StackPanel Orientation="Vertical">
<TextBlock Text="Student Details" VerticalAlignment="Top" HorizontalAlignment="Center" FontSize="16" FontWeight="Bold"> </TextBlock>
<StackPanel Margin="0,5" Orientation="Horizontal" >
<Label MinWidth="100" MaxWidth="110">Name:</Label>
<Border BorderBrush="Gray" BorderThickness="2">
<TextBox Name="nametextbox" Text="{Binding Name,Mode=TwoWay}" Width="auto" MinWidth="100" FontWeight="Black"></TextBox>
</Border>
</StackPanel>
Is it possible that you accidentally exchanged name and _name, using name in XAML for the binding?
Usually you have a public property with a capitalized name, and a private field with a non-capitalized name, optionally prefixed with an underscore as you did.
So, you should have
public string Name {
get { return _name; }
set { _name = value; OnPropertyChanged("Name"); }
{
private string _name = "";
Please check the following:
If you're not currently binding to name instead of _name;
Either if that is or is not the case, please fix your naming convention, because it is a source of errors, and every example you'll find follow the convention I included above.
In your XAML, you are binding "Name" property and in your code, you have created _name property. So, you need to change it to "Name" property in your code.
Just change your property as per below:
private string _name = "";
public string Name
{
get { return _name; }
set {
_name = value;
OnPropertyChanged("Name");
}
}
Try this and let me know.
I have used eventaggregator for this purpose, as we need to change the text in the text box dynamically when an event in a different view is fired. Below is the C# code of both the DropView(where we select student name from a list), and DetailsView(where we display the details). I publish events in Drop.xaml.cs and subscribe to those events in Details.xaml.cs
Drop.xaml.cs
public partial class Drop : UserControl
{
private IEventAggregator iEventAggregator;
public Drop(IEventAggregator ieventaggregator)
{
InitializeComponent();
iEventAggregator = ieventaggregator;
this.DataContext = this;
var doc = XDocument.Load("C:\\Users\\srinivasaarudra.k\\Desktop\\students.xml");
var names = doc.Descendants("Name");
foreach (var item in names)
{
droplist.Items.Add(item.Value);
}
}
public string name;
public string Naam
{
get { return name; }
set { name = value;
iEventAggregator.GetEvent<Itemselectedevent>().Publish(Naam);
}
}
public string grade;
public string Grade
{
get { return grade; }
set
{
grade = value;
iEventAggregator.GetEvent<gradeevent>().Publish(Grade);
}
}
public string dept;
public string Dept
{
get { return dept; }
set
{
dept = value;
iEventAggregator.GetEvent<deptevent>().Publish(Dept);
}
}
public static string str;
public static string Str
{
get { return str; }
set {
str = value;
}
}
private void droplist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var sel = droplist.SelectedValue;
Str=sel.ToString();
XmlDocument doc2 = new XmlDocument();
doc2.Load("C:\\Users\\srinivasaarudra.k\\Desktop\\students.xml");
var details = doc2.DocumentElement.SelectNodes("/Students/StudentDetails");
foreach (XmlNode node in details)
{
if (node.SelectSingleNode("Name").InnerText == Str)
{
Naam = node.SelectSingleNode("Name").InnerText;
Grade = node.SelectSingleNode("Grade").InnerText;
Dept = node.SelectSingleNode("Department").InnerText;
}
}
// Details det = new Details();
Details dt = new Details(iEventAggregator);
}
}
public class Itemselectedevent:Prism.Events.PubSubEvent<string>
{
}
public class gradeevent : Prism.Events.PubSubEvent<string>
{
}
public class deptevent : Prism.Events.PubSubEvent<string>
{
}
Details.xaml.cs
public partial class Details : UserControl,INotifyPropertyChanged
{
public IEventAggregator iEventAggregator;
public event PropertyChangedEventHandler PropertyChanged;
public static string name;
public static string dept;
public static string grade;
[Bindable(true)]
public string Naam
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Naam");
}
}
[Bindable(true)]
public string Grade
{
get { return grade; }
set
{
grade = value; OnPropertyChanged("Grade");
}
}
[Bindable(true)]
public string Dept
{
get { return dept; }
set
{
dept = value;
OnPropertyChanged("Dept");
}
}
public Details(IEventAggregator eventaggregator)
{
InitializeComponent();
this.iEventAggregator = eventaggregator;
iEventAggregator.GetEvent<Itemselectedevent>().Subscribe((str) => { Naam = str; });
iEventAggregator.GetEvent<gradeevent>().Subscribe((str) => { Grade = str; });
iEventAggregator.GetEvent<deptevent>().Subscribe((str) => { Dept = str; });
this.DataContext = this;
}
protected void OnPropertyChanged(string s)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(s));
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}

Xamarin Set Binding of EntryCell

I want to save the values that a user enters in the placeholder of an EntryCell using MVVM.
This is part of my .xaml
<TableView>
<TableView.Root>
<TableSection>
<EntryCell x:Name="HomeEC"
Label="HomeTeam"
Placeholder="{Binding Home, Mode=TwoWay}"
>
</EntryCell>
<EntryCell x:Name="AwayEC"
Label="AwayTeam"
Placeholder="{Binding Away, Mode=TwoWay}"
>
</EntryCell>
<EntryCell x:Name="BetEC"
Label="BetTeam"
Placeholder="{Binding Bet, Mode=TwoWay}"
>
</EntryCell>
<EntryCell x:Name="TypeEC"
Label="BetType"
Placeholder="{Binding Type, Mode=TwoWay}"
>
</EntryCell>
<EntryCell x:Name="OddEC"
Label="Odd"
Placeholder="{Binding Odd, Mode=TwoWay}"
>
</EntryCell>
</TableSection>
</TableView.Root>
</TableView>
And this is my ViewModel class
public string Home
{
set
{
home = value;
OnPropertyChanged("Home");
newMatch.HomeTeam = home;
}
}
public string Away
{
set
{
away = value;
OnPropertyChanged("Away");
newMatch.AwayTeam = away;
}
}
public string Bet
{
set
{
bet = value;
OnPropertyChanged("Bet");
newMatch.Bet = bet;
}
}
public string Type
{
set
{
type = value;
OnPropertyChanged("Type");
newMatch.BetType = type;
}
}
public string Odd
{
set
{
odd = value;
OnPropertyChanged("Odd");
newMatch.Odd = Decimal.Parse(odd);
}
}
public ICommand InsertBet;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
When I enter my values in the field in the UI, they do not get saved here in the VM. What am I doing wrong?
Thanks,
Dragos
InsertMatchVM.cs
public class InsertMatchVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string home, away, bet;
public Match newMatch = new Match();
public string Home
{
set
{
home = value;
OnPropertyChanged("Home");
newMatch.HomeTeam = home;
}
get
{
return home;
}
}
public string Away
{
set
{
away = value;
OnPropertyChanged("Away");
newMatch.AwayTeam = away;
}
get
{
return away;
}
}
public string Bet
{
set
{
bet = value;
OnPropertyChanged("Bet");
newMatch.Bet = bet;
}
get
{
return bet;
}
}
public ICommand InsertBet;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
Page1.Xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App2;assembly=App2"
x:Class="App2.Page1">
<ContentPage.BindingContext>
<local:InsertMatchVM/>
</ContentPage.BindingContext>
<TableView>
<TableView.Root>
<TableSection>
<EntryCell x:Name="HomeEC"
Label="HomeTeam"
Text="{Binding Home, Mode=TwoWay}"
Placeholder="Home"
>
</EntryCell>
<EntryCell x:Name="AwayEC"
Label="AwayTeam"
Text="{Binding Away, Mode=TwoWay}"
Placeholder="Away"
>
</EntryCell>
<EntryCell x:Name="BetEC"
Label="BetTeam"
Text="{Binding Bet, Mode=TwoWay}"
Placeholder="Bet"
>
</EntryCell>
</TableSection>
</TableView.Root>
</TableView>
</ContentPage>
App.cs
public class App : Application
{
public App()
{
MainPage = new Page1();
}
}
Match.cs
public class Match
{
public string HomeTeam { get; set; }
public string AwayTeam { get; set; }
public string Bet { get; set; }
}

MVVM Bindings not working properly

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

Categories