In xaml, I set my title to a value but it doesn't show in the window when I launch my app.
Similar to this post:
https://stackoverflow.com/questions/14397728/wpf-mvvm-bind-window-title-to-property#:~:text=The%20title%20is%20bound%20to%20window-viewmodel%20and%20the,because%20it%20inherits%20the%20DataContext%20of%20the%20window.
But I removed the datacontext and it didn't change anything. It showing "MyTitle" like in the preview is the desired behavior.
<Window x:Class="RED.Views.ShellView"
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:model="clr-namespace:RED.ViewModels"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
Height="700" Width="900" MinWidth="1100" MinHeight="700" Background="Gray" WindowStartupLocation="CenterScreen"
Title="MyTitle">
<!--d:DataContext="{x:Type model:ShellViewModel}"-->
<!--more markup-->
</Window>
This shows in the editor:
But launching the application shows the namespace name followed by some other stuff:
I am using Caliburn.micro, which I suspect is part of my issue but I cannot figure out how to get the title to update. This is my only window control in the whole project. My other xaml files are UserControls.
The ShellViewModel.cs file is 90% unused code that is a carry over from a tutorial I did. Here is that code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Caliburn.Micro;
using RED.Models;
using RED.Views;
namespace RED.ViewModels
{
public class ShellViewModel : Conductor<object>
{
//private string _lblLogged;
//private string lblLoggedInAs;
private string _firstName = "Tim"; // Don't change this
private string _lastName;
private BindableCollection<PersonModel> _people = new BindableCollection<PersonModel>();
private PersonModel _selectedPerson;
public ShellViewModel() //Constructor
{
People.Add(new PersonModel { FirstName = "Tim", LastName = "Corey" });
People.Add(new PersonModel { FirstName = "Bill", LastName = "Jones" });
People.Add(new PersonModel { FirstName = "Sam", LastName = "Yet" });
}
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
NotifyOfPropertyChange(() => FirstName);
NotifyOfPropertyChange(() => FullName); //Whenever a value of first name is changed, update fullname
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
NotifyOfPropertyChange(() => LastName);
NotifyOfPropertyChange(() => FullName); //Whenever a value of last name is changed, update fullname
}
}
public String FullName
{
get { return $"{ FirstName } { LastName }"; }
}
public BindableCollection<PersonModel> People
{
get { return _people; }
set { _people = value; }
}
public PersonModel SelectedPerson
{
get { return _selectedPerson; }
set
{
_selectedPerson = value;
NotifyOfPropertyChange(() => SelectedPerson);
}
}
//Return true or true for yes we can clear the text
public bool CanClearText(string firstName, string lastName)
{
//return !String.IsNullOrWhiteSpace(firstName) || !String.IsNullOrWhiteSpace(lastName);
if (String.IsNullOrWhiteSpace(firstName) && String.IsNullOrWhiteSpace(lastName))
{
return false;
}
else
{
return true;
}
}
//Perameters should start with lowercase, properties should start with uppercase
public void ClearText(string firstName, string lastName)
{
FirstName = "";
LastName = "";
}
public void btn_Phonebook()
{
if (Globals.isLoggedIn == true)
{
ActivateItem(new PhonebookViewModel());
}
else
{
MessageBox.Show("Please sign in to use the phonebook.");
}
}
public void btn_eRCPS()
{
ActivateItem(new WelcomeViewModel());
}
}
}
Everything works as expected except for this window title. Please let me know if there are other code bits that would be helpful and I will add them. Thanks!
In Caliburn.Micro, you should set the DisplayName property of the Conductor to change the window title:
public ShellViewModel() //Constructor
{
DisplayName = "MyTitle";
People.Add(new PersonModel { FirstName = "Tim", LastName = "Corey" });
People.Add(new PersonModel { FirstName = "Bill", LastName = "Jones" });
People.Add(new PersonModel { FirstName = "Sam", LastName = "Yet" });
}
I personally feel caliburn micro uses some bad techniques. I far prefer the community mvvm toolkit.
The work round for this is to explicitly bind the window title.
Title="{Binding WindowTitle}"
And, of course, add a WindowTitle string property to your viewmodel which returns a more suitable title.
You could probably override tostring on your viewmodel.
Related
I have a simple class User like below:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string FullName
{
get
{
return Name + " " + Surname;
}
}
}
Then I have form frmProcess, which displays list of Users in combobox, like below. The problem is, that if I set DisplayMember to FullName then what is displayed is UserId column. What's weird is that if I set DisplayMember to Surname, then Surname is displayed. What am I doing wrong?
public partial class frmProcess : Form
{
List<User> Users;
private async void frmProcess_Load(object sender, EventArgs e)
{
Users = new List<User>();
User A = new User { UserId = 1, Name = "Michael", Surname = "Smith" };
User B = new User { UserId = 2, Name = "John", Surname = "Johnson" };
Users.Add(A);
Users.Add(B);
cmbStartedBy.DataSource = Users;
cmbStartedBy.DisplayMember = "FullName";
cmbStartedBy.ValueMember = "UserId";
}
}
I have run your exact code in a winforms application in VS2013 and get this:
EDIT: The only difference is the async on Form load.
Entire code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
List<User> Users;
private void Form1_Load(object sender, EventArgs e)
{
Users = new List<User>();
User A = new User { UserId = 1, Name = "Michael", Surname = "Smith" };
User B = new User { UserId = 2, Name = "John", Surname = "Johnson" };
Users.Add(A);
Users.Add(B);
comboBox1.DataSource = Users;
comboBox1.DisplayMember = "FullName";
comboBox1.ValueMember = "UserId";
}
}
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string FullName
{
get
{
return Name + " " + Surname;
}
}
}
}
Ok, found the bug. When I was posting my question I simplified my class and removed, among others, the data annotations. Surprisingly, this made the code work correctly. As it turns out, the problem was caused by FullName property being marked as [Browsable(false)]. I marked it unbrowsable so that this property wasn't displayed in DataGridViews, didn't realize the impact is also on comboboxes.
public class User
{
[DisplayName("ID")]
public int UserID { get; set; }
[DisplayName("Imie")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Pole imie nie może być puste!")]
public string Name { get; set; }
[DisplayName("Nazwisko")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Pole nazwisko nie może być puste!")]
public string Surname { get; set; }
[Browsable(false)]// <-- this was causing the issue
public string FullName
{
get
{
return Name + " " + Surname;
}
}
}
I'm facing this weird problem.It looks like well known question. I tried to find the solution. It took one whole day. But still no use. All the solutions I tried didn't help me.
<ListBox ItemsSource="{Binding ElementName=root,Path=ItemsSource,UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Category" Background="Coral"></ListBox>
root is the name of the User Control and ItemsSource is the dependency Property.
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(LineBarChart));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set {
SetValue(ItemsSourceProperty, value); }
}
Now, In MainWindow.xaml,
I created an instance of the User Control and Binded to the ItemsSource of Usercontrol this way..
ItemsSource="{Binding ElementName=Window,Path=LineBarData,UpdateSourceTrigger=PropertyChanged}"
where windows is the name of the Main Window
The code behind of the main window is:
public partial class MainWindow : Window
{
private ObservableCollection<LineBarChartData> lineBarData;
internal ObservableCollection<LineBarChartData> LineBarData
{
get
{
return lineBarData;
}
set
{
lineBarData = value;
}
}
public MainWindow()
{
InitializeComponent();
LineBarData = new ObservableCollection<LineBarChartData>();
LineBarData.Add(new LineBarChartData() { Category = "January", ValueX = 10, ValueY = 50 });
LineBarData.Add(new LineBarChartData() { Category = "February", ValueX = 20, ValueY = 60 });
LineBarData.Add(new LineBarChartData() { Category = "March", ValueX = 30, ValueY = 70 });
LineBarData.Add(new LineBarChartData() { Category = "April", ValueX = 40, ValueY = 80 });
}
And the LineBarChartData class is like below
public class LineBarChartData : INotifyPropertyChanged
{
private string _category;
public string Category
{
get { return this._category; }
set { this._category = value; this.OnPropertyChanged("Category"); }
}
private double _valueX;
public double ValueX
{
get { return this._valueX; }
set { this._valueX = value; this.OnPropertyChanged("ValueX"); }
}
private double _valueY;
public double ValueY
{
get { return this._valueY; }
set { this._valueY= value; this.OnPropertyChanged("ValueY"); }
}
//private Brush _color;
//public Brush Color
//{
// get { return this._color; }
// set { this._color = value; this.OnPropertyChanged("Color"); }
//}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Nothing is being displayed in the listbox. I am unable to find my mistake. Please help!
Thanks.
WPF data binding only works with public properties, so
internal ObservableCollection<LineBarChartData> LineBarData { get; set; }
should be
public ObservableCollection<LineBarChartData> LineBarData { get; set; }
You might also drop the backing field and write the property (as read only) like this:
public ObservableCollection<LineBarChartData> LineBarData { get; }
= new ObservableCollection<LineBarChartData>();
Then add values like this:
public MainWindow()
{
InitializeComponent();
LineBarData.Add(new LineBarChartData() { ... });
...
}
As a note, setting UpdateSourceTrigger=PropertyChanged on a Binding only has an effect when it is a TwoWay or OneWayToSource binding, and the Binding actually updates the source property. This is not the case in your Bindings.
I'm using MVVM pattern, developing my WPF application. I also use Entity Framework as ORM. Here're my models (EF):
public class User : BaseEntity
{
public string Name { get; set; }
public int OfficeId { get; set; }
public Office Office { get; set; }
}
public class Office : BaseEntity
{
public string Name { get; set; }
public int DepartmentId { get; set; }
public Department Department { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class Department : BaseEntity
{
public string Name { get; set; }
public virtual ICollection<Office> Offices { get; set; }
}
Let's assume, that I've got an instance of User class from my context:
var userInstance = context.Get<User>().Single(user => user.ID == 1);
Now I'd like to pass this instance to my View to make some changes for concrete user (called, for example, UserEditView), so I have to create a UserModel class to deal with User data according to MVVM. So, here's what I think I have to write in my code:
public class UserModel : ObservableObject
{
private User user;
public string Office Office
{
get
{
return this.user.Office.Name;
}
set
{
//what shoud I write Here??
if(value != user.Office)
{
user.Office=value;
OnPropertyChanged("Office");
}
}
}
}
I'm really frustrated! How should I deal with that? There're thousands of examples, but they are so simple. I'm wondering what should I do to have a ComboBox in my EditView with a list of all Offices, existing in my DB. And list of Offices should depend on another one Combobox, which contains a list of Departments.
But where should I get this lists from?
Should I pass a collection from my UserModel? Or what?
Can anybody give me a simple example about how to do this correctly?
PS: Of course, I know couple ways to implement such behaviour, but in that case my code seems to be ugly and not maintainable. Please, help. Thanks a lot!
this is depends on your DB architecture. Here is some common suggestion (but there can be a lot of others).
Don't panic - you have a correct question.
Create the view model set it to be a main view model of your window.
In your view model create two collections Users (containing UserModels) and Departments (containing DepartmentMode), since you want to change offices each time you re-select department, you don't need the Offices collection in main view model.
Pull each collection data from your data base.
Implement each model with INPC.
Take in account the WPF MVVM best practices.
Apply a correct bindings.
And be happy - you are a programmer.
Updates - 1
XAML code
<Grid x:Name="LayoutRoot">
<Grid.DataContext>
<someBindingExampleSoHelpAttempt:MainViewModel/>
</Grid.DataContext>
<ListView ItemsSource="{Binding Users}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="someBindingExampleSoHelpAttempt:UserModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding Name, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding LastName, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/>
<ComboBox Grid.Column="2"
IsTextSearchEnabled="True"
IsTextSearchCaseSensitive="False"
StaysOpenOnEdit="True"
TextSearch.TextPath="DepartmentName"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListView}}, Path=DataContext.Departments}"
SelectedValue="{Binding Department}"
DisplayMemberPath="DepartmentName"
IsEditable="True"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
<ComboBox Grid.Column="3"
IsTextSearchEnabled="True"
IsTextSearchCaseSensitive="False"
StaysOpenOnEdit="True"
IsEditable="True"
TextSearch.TextPath="OfficeName"
ItemsSource="{Binding OfficesCollection}"
SelectedValue="{Binding Office}"
DisplayMemberPath="OfficeName"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView></Grid>
VM and models
public class MainViewModel:BaseObservableObject
{
private DepartmentModel _selectedDepartment;
private OfficeModel _selectedOffice;
public MainViewModel()
{
Dal = new DataLayer();
Users = new ObservableCollection<UserModel>();
Departments = new ObservableCollection<DepartmentModel>(Dal.GetAllDepartments());
InitUsersCollection();
}
private void InitUsersCollection()
{
if(Departments == null) return;
Departments.ToList().ForEach(model =>
{
model.Offices.ToList().ForEach(officeModel =>
{
if (officeModel.Users == null) return;
officeModel.Users.ToList().ForEach(userModel => Users.Add(userModel));
});
});
}
public ObservableCollection<UserModel> Users { get; set; }
public ObservableCollection<DepartmentModel> Departments { get; set; }
private DataLayer Dal { get; set; }
}
public class DataLayer
{
public List<DepartmentModel> GetAllDepartments()
{
//pull and map your using your DB service
//For example:
return new List<DepartmentModel>
{
new DepartmentModel
{
DepartmentId = 1,
DepartmentName = "A",
Offices = new ObservableCollection<OfficeModel>
{
new OfficeModel
{
DepartmentId = 1,
OfficeName = "AA",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "Avicenna", LastName = "Abu Ali Abdulloh Ibn-Sino"},
new UserModel {Name = "Omar", LastName = "Khayyam"},
new UserModel {Name = "RAMBAM", LastName = "Moshe ben Maimon"}
})
},
new OfficeModel
{
DepartmentId = 1,
OfficeName = "AB",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "Leo", LastName = "Tolstoi"},
new UserModel {Name = "Anton", LastName = "Chekhov"},
})},
}
},
new DepartmentModel
{
DepartmentId = 2,
DepartmentName = "B",
Offices = new ObservableCollection<OfficeModel>
{
new OfficeModel
{
DepartmentId = 2, OfficeName = "BA",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "B", LastName = "O"},
new UserModel {Name = "B", LastName = "N"},
}),
},
new OfficeModel
{
DepartmentId = 2, OfficeName = "BB",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "John", LastName = "Walker"},
new UserModel {Name = "Gregory", LastName = "Rasputin"},
}),
},
}
},
new DepartmentModel
{
DepartmentId = 3,
DepartmentName = "C",
Offices = new ObservableCollection<OfficeModel>
{
new OfficeModel {DepartmentId = 3, OfficeName = "CA"},
new OfficeModel {DepartmentId = 3, OfficeName = "CB"},
new OfficeModel {DepartmentId = 3, OfficeName = "CC"}
}
}
};
}
}
public class OfficeModel:BaseObservableObject
{
private int _departmentModel;
private string _officeName;
private DepartmentModel _department;
private ObservableCollection<UserModel> _users;
public int DepartmentId
{
get { return _departmentModel; }
set
{
_departmentModel = value;
OnPropertyChanged();
}
}
public DepartmentModel Department
{
get { return _department; }
set
{
_department = value;
OnPropertyChanged();
}
}
public string OfficeName
{
get { return _officeName; }
set
{
_officeName = value;
OnPropertyChanged();
}
}
public ObservableCollection<UserModel> Users
{
get { return _users; }
set
{
_users = value;
OnPropertyChanged(()=>Users);
}
}
}
public class DepartmentModel:BaseObservableObject
{
private string _departmentName;
public string DepartmentName
{
get { return _departmentName; }
set
{
_departmentName = value;
OnPropertyChanged();
}
}
public int DepartmentId { get; set; }
public ObservableCollection<OfficeModel> Offices { get; set; }
}
public class UserModel:BaseObservableObject
{
private string _name;
private string _lastName;
private DepartmentModel _department;
private OfficeModel _office;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged();
}
}
public DepartmentModel Department
{
get { return _department; }
set
{
_department = value;
OnPropertyChanged();
OnPropertyChanged(()=>OfficesCollection);
}
}
public ObservableCollection<OfficeModel> OfficesCollection
{
get { return Department.Offices; }
}
public OfficeModel Office
{
get { return _office; }
set
{
_office = value;
OnPropertyChanged();
}
}
}
/// <summary>
/// implements the INotifyPropertyChanged (.net 4.5)
/// </summary>
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
But please take in account that this is only one of hundreds ways to do that.
The SO here if you will need the code example.
Regards.
I have a project in WPF with the MVVM-Pattern.
The view has a listview of Persons(FirstName, LastName, Town) and next to the list are the details of the person(FirstName,LastName,ZIP) with a button(Save).
If you click to a person on the left side, the person details on the right side will load automatically.
In the ViewModel I have an ObservableCollection of Person-Models. (Person list)
The Person Model includes some propertys like FirstName, LastName, Town, Zip. (Details).
When I change the ZIP, the Town will updated automatically(in the setter switch-case) e.g. ZIP '11111' Town 'Town1' / ZIP '22222' Town 'Town2'.
The Person Model includes also an ICommand "SavePerson" to Save Changes.
Now when i click to an item in the listview the details will load automatically.
When I change the FirstName or LastName and click "Save" the listview will change the First and the LastName of the selected item, that's ok.
Now when I change the ZIP from '12345' into '11111' the town in the listview is still the old one and not 'Town1'.
Have you an idea to fix this problem, without to implement the INotifyPropertyChanged-Interface in the Model?
Some code:
Model:
public class Person
{
private string _firstName = string.Empty;
private string _lastName = string.Empty;
private string _zip = string.Empty;
private string _town = string.Empty;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
public string LastName
{
get { return _lastName; }
set { _lastName= value; }
}
public string ZIP
{
get { return _zip; }
set
{
switch (value)
{
case "11111":
this.Town = "Town1";
break;
case "22222":
this.Ort = "Town2";
break;
default:
break;
}
_zip = value;
}
}
public string Town
{
get { return _town; }
set { _town= value; }
}
public ICommand SaveNameCommand
{
get
{
return new DelegateCommand((param) => this.SaveName(param));
}
}
private void SaveName(object parameter)
{
string[] param = ((string)parameter).Split(new char[] { ':' });
FirstName = param[0];
LastName = param[1];
PLZ = param[2];
}
}
ViewModel:
public class PersonList
{
private readonly ObservableCollection<Person> _persons = new ObservableCollection<Person>();
private Person _currentSelectedPerson = new Person();
public PersonList()
{
this._persons.Add(new Person() { FirstName = "First1", LastName = "Last1", Ort = "Ort1", PLZ = "112" });
this._persons.Add(new Person() { FirstName = "First2", LastName = "Last2", Ort = "Ort2", PLZ = "122" });
this._persons.Add(new Person() { FirstName = "First3", LastName = "Last3", Ort = "Ort3", PLZ = "1132" });
}
public IEnumerable<Person> Persons
{
get { return this._persons; }
}
}
Since your Model should be loosely-coupled from your ViewModel, it makes sense that you might not want to implement INotifyPropertyChanged in your Model since it's most commonly associated with WPF; however, it's a C# interface and can be used in any type of application, so there's no harm implementing it. In fact, I'd suggest it's probably the best way. However, if you really don't want to implement it in your model classes, consider an event-subscriber model, where the Model raises an event when changed, and the ViewModel subscribes to it.
model.ValuesChanged += model_ValuesChanged;
private void model_ValuesChanged(object sender, EventArgs e)
{
RaisePropertyChanged("MyProperty");
}
I have absolutely no idea why you would want to not implement the INotifyPropertyChanged interface on your model class(es). Really, your only other option would be to implement it in your view model and expose all of your model properties there:
public string FirstName
{
get { return _currentSelectedPerson .FirstName; }
set { _currentSelectedPerson .FirstName = value; NotifyPropertyChanged("FirstName"); }
}
public string LastName
{
get { return _currentSelectedPerson .LastName; }
set { _currentSelectedPerson .LastName= value; NotifyPropertyChanged("LastName"); }
}
...
WPF and the INotifyPropertyChanged interface go hand in hand... at some stage, you're going to have to implement it.
The model Should implement INotifyPropertyChanged
chack INotifyPropertyChanged WPF
any other search of INotifyPropertyChanged will do as well
You need notification your View about changed in ViewModel.
For this use INotifyPropertyChanged. Any class that implements this interface,
notifies any listeners when a property has changed.
So you need to modify our Person class a little bit more:
public class Person : INotifyPropertyChanged
{
private string _firstName = string.Empty;
private string _lastName = string.Empty;
private string _zip = string.Empty;
private string _town = string.Empty;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName= value;
RaisePropertyChanged("LastName");
}
}
public string ZIP
{
get { return _zip; }
set
{
switch (value)
{
case "11111":
this.Town = "Town1";
break;
case "22222":
this.Town = "Town2";
break;
default:
break;
}
_zip = value;
RaisePropertyChanged("LastName");
RaisePropertyChanged("Town");
}
}
public string Town
{
get { return _town; }
set
{
_town= value;
RaisePropertyChanged("Town");
}
}
public ICommand SaveNameCommand
{
get
{
return new DelegateCommand((param) => this.SaveName(param));
}
}
private void SaveName(object parameter)
{
string[] param = ((string)parameter).Split(new char[] { ':' });
FirstName = param[0];
LastName = param[1];
PLZ = param[2];
}
}
I have a textbox and a Datagrid. The datagrid has two columns name and Email address. I want to Filter the datagrid values with the value in the textbox.
You can use a ICollectionView for the DataGrid ItemSource then you can apply a Filter predicate and refesh the list when needed.
Here is a very quick example.
Xaml:
<Window x:Class="WpfApplication10.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="188" Width="288" Name="UI" >
<StackPanel DataContext="{Binding ElementName=UI}">
<TextBox Text="{Binding FilterString, UpdateSourceTrigger=PropertyChanged}" />
<DataGrid ItemsSource="{Binding DataGridCollection}" />
</StackPanel>
</Window>
Code:
namespace WpfApplication10
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ICollectionView _dataGridCollection;
private string _filterString;
public MainWindow()
{
InitializeComponent();
DataGridCollection = CollectionViewSource.GetDefaultView(TestData);
DataGridCollection.Filter = new Predicate<object>(Filter);
}
public ICollectionView DataGridCollection
{
get { return _dataGridCollection; }
set { _dataGridCollection = value; NotifyPropertyChanged("DataGridCollection"); }
}
public string FilterString
{
get { return _filterString; }
set
{
_filterString = value;
NotifyPropertyChanged("FilterString");
FilterCollection();
}
}
private void FilterCollection()
{
if (_dataGridCollection != null)
{
_dataGridCollection.Refresh();
}
}
public bool Filter(object obj)
{
var data = obj as TestClass;
if (data != null)
{
if (!string.IsNullOrEmpty(_filterString))
{
return data.Name.Contains(_filterString) || data.Email.Contains(_filterString);
}
return true;
}
return false;
}
public IEnumerable<TestClass> TestData
{
get
{
yield return new TestClass { Name = "1", Email = "1#test.com" };
yield return new TestClass { Name = "2", Email = "2#test.com" };
yield return new TestClass { Name = "3", Email = "3#test.com" };
yield return new TestClass { Name = "4", Email = "4#test.com" };
yield return new TestClass { Name = "5", Email = "5#test.com" };
yield return new TestClass { Name = "6", Email = "6#test.com" };
yield return new TestClass { Name = "7", Email = "7#test.com" };
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
public class TestClass
{
public string Name { get; set; }
public string Email { get; set; }
}
}
Result: