I try to adopt entity-level validation (attributes validation on properties on entities) by create ViewModel that expose that Entity.
public class MyViewModel
{
public MyEntity MyEntity { get; set; }
}
I set binding in xaml to, this xaml page set its DataContext to instance of MyViewModel
TextBlock Text="{Binding MyEntity.MyProperty}"
When I load MyEntity from database and set it to MyViewModel, nothing happen. I also call NotifyPropertyChanged("MyEntity"); and it still nothing happen.
I try again by create MyProperty in MyViewModel
public class MyViewModel
{
private MyEntity MyEntity { get; set; }
public string MyProperty
{
get { return this.MyEntity.MyProperty; }
set { this.MyEntity.MyProperty = value; }
}
}
And changed xaml to bind to MyProperty. This time when I call NotifyPropertyChanged("MyProperty "); View get update correctly, when I input incorrect data, it has ValidationErrors at MyEntity but View don't raise that error (not show red border)
I want to know how can I get entity-level validation working with MVVM.
Hi
you must change the definition of ViewModel such as
public class MyViewModel:IDataErrorInfo
{
}
and implement interface.
this force View to show red border on error.
wish to help.
Related
I am using WPF and I have a custom datagrid. What I would like to do is add a property (CustomGridCommands) to that grid which I can set in xaml from any view.
What I have at the moment is as follows (I have changed the code a bit to simplify it):
Custom grid C# code:
public class CustomWPFDataGrid : DataGrid, INotifyPropertyChanged
{
public static readonly DependencyProperty CustomContextMenuCommandsProperty =
DependencyProperty.Register("CustomContextMenuCommands",
typeof (ObservableCollection<WPFBaseCommand>),
typeof (CustomWPFDataGrid));
[Bindable(true)]
public ObservableCollection<WPFBaseCommand> CustomContextMenuCommands
{
get { return (ObservableCollection<WPFBaseCommand>) GetValue(CustomContextMenuCommandsProperty); }
set { SetValue(CustomContextMenuCommandsProperty, value); }
}
...
...
}
XAML code:
<common:CustomWPFDataGrid
ItemsSource="{Binding Path=ItemList}"
CustomContextMenuCommands="{Binding Path=CustomGridCommands, Mode=TwoWay}">
....
</common:CustomWPFDataGrid >
The object I have bound to the view that contains the grid is as follows:
public class TestViewModel
{
public ObservableCollection<TestDisplayViewModel> ItemList { get; set; }
public ObservableCollection<WPFBaseCommand> CustomGridCommands;
public TestViewModel()
{
... population of objects here
}
When I run this, and check the value of the property (CustomContextMenuCommands) in the datagrid, it is always null.
Any ideas what I am doing wrong?
EDIT
The setter of the "CustomContextMenuCommands" is never hit.
CustomGridCommands in your ViewModel is a field, View cannot use it. If you make it a public property, then it will become accessible. More details on what can be used as binding source can be found on MSDN - Binding Sources.
If using WPF 4.5, static properties can also be used for binding, as described in release notes.
I have the following visual tree
MainWindow
|--------UserControl
|----------ChildListView1
|--------ChildListView2
When user selects an item in ChildListView1, The ViewModel object of that item will be taken and it has a property called ConfigParams which has to be bound to ChildListView2.
Here is my view model
public class Equipment
{
public string Name {get; set;} //TODO: Change to Raise PropertyChanged on set
public ObservableCollection<ConfigParams> {get;set;}
}
Here is MainWindow's view model
public class MainViewModel
{
public ObservableCollection<Equipment> Equipments {get;set;}
}
In the xaml.cs of my UserControl I added the following property
public ListView ListInstances { get { return ChildListView1; } }
Added the following ItemsSource binding to my ChildListView2
ItemsSource="{Binding ListInstances.SelectedItem.ConfigParams, ElementName=MyUserControlName}"
I'm following MVVM pattern. I have a listview control which has multiple checkboxes. my viewmodel has collection of Student which is bounded to listview control.
public ObservableCollection<Student> students{ get; private set; }
private ObservableCollection<Student> _displays { get; set; }
viewmodel doesn't know anything about the view so it doesn't access to the listview control
I tried by defining the Student class by below
public class Student
{
public string Name{ get; set; }
public string class { get; set; }
}
In viewmodel, i want to perform some action when user select/unselect the checkbox.
how can I get which items are checked or not, how can i get selected item state in viewmodel?
I'm following mvvm pattern.
In WPF, we generally use data binding. This means that ideally, you would have data bound a property of your Student class to a Checkbox in the UI:
public class Student : INotifyPropertyChanged
{
public bool IsSomething { get; set; } // Implement INotifyPropertyChanged here
...
}
...
<Checkbox IsChecked="{Binding IsSomething}" />
If you do this, then you can find out which Checkboxes were checked simply by looking at the relevant Student object from your view model:
bool isSomething = CurrentStudent.IsSomething;
If you want to react to the changing value, then you just have to monitor the property for changes:
public bool IsSomething
{
get { return isSomething; }
set
{
if (value != isSomething)
{
isSomething= value;
NotifyPropertyChanged("IsSomething");
if (isSomething) CheckedBoxWasChecked();
else CheckedBoxWasUnChecked();
}
}
}
Can you check multiple items at a time?
If not, you can simple add a SelectedItem property to your view model and bind the SelectedItem property of the listView to the SelectedItem property of the view model.
If you need to be able to check more than one item at a time, you can add a boolean IsSelected property to the Student class. Then in your data template for the list view, bind the IsChecked property of the checkbox to the IsSelected property of the Student.
Please make sure your view model and student class implement INotifyPropertyChanged, etc.
As a new one to WPF, I start my MVVM travel recently. I can understand the orginal intension about why we need MVVM, but some of the implementation detail still confuse me a lot.
Here is one of my questions:
How should I export the property in model to View via ViewModel
I can show some of my idea here, so please share your view with me.
Here is one of my implementation:
class MyModel : INotifyPropertyChanged
{
private String _name;
public String Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
class MyViewModel
{
private MyModel _model;
public MyModel Model
{
get { return _model; }
set { _model = value; }
}
}
I think the problem for this is we do not decouple the view from model. And the view need to know every detail about the model implementation to accomplish the Binding process. And exporting the propert in Model directly to view from ViewModel cannot be treat as a good design in my opinion.
So I hope you can share your experience on the design about this topic.
BTW,
If we export many object, such as, a List of MyModel object to view from viewmodel, how can I implement this to decouple the view from model?
Not your Model, but your ViewModel shall implement INotifyPropertyChanged. Then you can use Binding in the View to get the Data from the ViewModel.
In your View / XAML you have statements like
... Content="{Binding myViewModelProperty}" ...
depending on what you are binding.
myViewModelProperty has to be a public property in your ViewModel
public string myViewModelProperty { get; set; }
Do not forget to call RaiseNotifyPropertyChanged (or what your handler is called) in the setter to get updates in the View.
private string myViewModelField;
public string myViewModelProperty
{
get
{
return myViewModelField;
}
set
{
myViewModelField = value;
RaiseNotifyPropertyChanged(() => myViewModelProperty);
}
}
** Update **
Lists are typically "exported" via ObservableCollection<Type>.
Ideally Type is some ViewModel here, created with data from the model to
be shown in your View. You can imagine the ViewModel as Adapter between
your model and your view.
This is not a strict rule, but in my case I prefer to implement INotifyPropertyChanged in the ViewModels and to leave the Models as simple POCOs.
It can be annoying to "repeat" the properties of the Model in the ViewModel, but :
Generally you don't need to expose all the properties to the View.
It allows you to add additional code like user input validation in your VM and keep your Model "clean".
So in your example it would be:
class MyModel
{
public String Name
{
get;
set;
}
}
class MyViewModel : ViewModelBase //let's say you have this base class in your framework
{
private MyModel model;
public MyViewModel(MyModel model)
{
this.model = model;
}
public string Name
{
get
{
return this.model.Name;
}
set
{
if(IsValidInput(value)
{
this.model.Name = value;
this.RaisePropertyChanged("Name"); // the ViewModelBase base class provide this helper.
}
}
}
}
About your second question, ObservableCollection is usually a nice way to expose a collection of Models to the view:
class ContactListViewModel
{
public ObservableCollection<MyModel> Contacts { get; private set;}
}
You can simply bind your property on view wiuth Model.Name
I would like to know what is correct using of model class in in view model. As MVVM I use Caliburn Micro.
First alternative.
Model class:
public class CurrentUser : IDataErrorInfo
{
public string Nick { get; set; }
public string Password { get; set; }
//...
}
Using model in view model class:
[Export(typeof(ILogOnViewModel))]
public class LogOnViewModel : Screen
{
public CurrentUser CurrentUser { get; set; }
//bind on control in view
public string CurrentNick
{
get { return CurrentUser.Nick; }
set
{
CurrentUser.Nick = value;
NotifyOfPropertyChange(() => CurrentNick);
}
}
//bind on control in view
public string CurrentPassword
{
get { return CurrentUser.Password; }
set
{
CurrentUser.Password = value;
NotifyOfPropertyChange(() => CurrentPassword);
}
}
}
Second alternative:
Model class:
public class CurrentUser : IDataErrorInfo, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public string Nick
{
get { return _nick; }
set
{
_nick = value;
NotifyPropertyChanged("Nick");
}
}
public string Password
{
get { return _password; }
set
{
_password = value;
NotifyPropertyChanged("Password");
}
}
//...
}
Using model class in view model class:
[Export(typeof(ILogOnViewModel))]
public class LogOnViewModel : Screen
{
//bind on UI control
public CurrentUser CurrentUser { get; set; }
}
The first alternative would be better, since it encapsulates your model better from the View.
But you should implement IDataErrorInfo and INotifyPropertyChanged on the ViewModel, since the ViewModel should be the object that notifies your user interface of changes and errors.
I would prefer the first approach. There are a few reasons why:
A Model should never be accessible to View.
In theory, a ViewModel wraps/facades all properties required to be bound to View from Model. It adds any additional properties, collections and commands required to facilitate View's functionality and while preventing putting code in code behind.
IDataErrorInfo and INotifyPropertyChanged facilitate View not ViewModel. And since View only communicates with ViewModel, they should be inside ViewModel.
I would use the second approach. If you are looking for sample applications that use the second approach then you might find the WPF Application Framework (WAF) project interesting.
I'd recommend starting off with the second approach. It could save you from typing out a lot of repetitive bridging properties. If you encounter a property that needs to be wrapped on the View Model, then do so for that property then update the View's binding(s). Both your Model and View Model can implement IDataErrorInfo and INotifyPropertyChanged. The latter is quite useful when some logic in your Model changes a property since it will then be propagated to the View. Implementing those interfaces via base classes, you could have both a ModelBase and a ViewModelBase abstract classes, where the latter derives from the former.