MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand :...
Transcript of MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand :...
![Page 1: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/1.jpg)
Philip Japikse (@skimedic)
www.skimedic.com/blog
Microsoft MVP, ASPInsider, MCSD, MCDBA, CSM, CSP
Principal Consultant/Architect, Strategic Data Systems
MODEL-VIEW-VIEWMODEL FOR WPF
Philip Japikse (@skimedic) [email protected] www.skimedic.com/blog Microsoft MVP, ASPInsider, MCSD, MCDBA, CSM, CSP
![Page 2: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/2.jpg)
Principal Consultant/Architect, Strategic Data Systems
http://www.sds-consulting.com
Developer, Coach, Author, Teacher
http://bit.ly/pro_csharp
Microsoft MVP, ASPInsider, MCSD, MCDBA, CSM, CSP
Founder, Agile Conferences, Inc.
http://www.dayofagile.org
President, Cincinnati .NET User’s Group
Phil.About()
![Page 3: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/3.jpg)
Hosted by Phil Japikse, Steve Bohlen, Lee Brandt, James
Bender
Website: www.hallwayconversations.com
iTunes: http://bit.ly/hallway_convo_itunes
Feed Burner: http://bit.ly/hallway_convo_feed
Also available through Windows Store
Hallway Conversations Podcast
![Page 4: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/4.jpg)
THE MODEL VIEW VIEW-MODEL PATTERN
![Page 5: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/5.jpg)
The data of the application
(Can be) Optimized for storage
MODELS
![Page 6: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/6.jpg)
Accepts Interactions from User
Returns results of interactions back to
user
VIEWS
![Page 7: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/7.jpg)
Façade for individual models
Transport mechanism for models
VIEW MODEL – JOB 1
![Page 8: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/8.jpg)
Process Incoming requests
Perform changes to the model
VIEW MODEL – JOB 2
![Page 9: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/9.jpg)
WHY MVVM?
![Page 10: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/10.jpg)
DON’T REPEAT YOURSELF
![Page 11: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/11.jpg)
SEPARATION OF CONCERNS
![Page 12: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/12.jpg)
MVVM != 0 CODE BEHIND
Temper your actions with wisdom
Code Behind is hard to test
Complicated markup is hard to understand
![Page 13: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/13.jpg)
IMPLEMENTING MVVM IN WPF
![Page 14: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/14.jpg)
THE COMMAND PATTERN
![Page 15: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/15.jpg)
ENCAPSULATING LOGIC
Wire commands through markup
Reuse command code (where appropriate)
Leverage converters
IValueConverter
IMultiValueConverter
![Page 16: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/16.jpg)
IMPLEMENTING ICOMMAND BY HAND-WPF
public class DoSomethingCommand : CommandBase
{
public DoSomethingCommand()
{
//do something if necessary
}
public override void Execute(
object parameter)
{
_messenger.Show("Clicked!");
}
public override bool CanExecute(
object parameter)
{
return (parameter != null && (bool)
parameter);
}
}
public abstract class CommandBase : ICommand { public abstract void Execute(object parameter); public abstract bool CanExecute(object parameter);
public event EventHandler CanExecuteChanged{
add { CommandManager.RequerySuggested +=
value; }
remove { CommandManager.RequerySuggested -= value;
} }
}
![Page 17: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/17.jpg)
ROUTED AND DELEGATE/RELAY COMMANDS
Both remove the need to create a new class for the command logic
Routed Commands
Leverage routed events allowing handlers and invokers to be disconnected – don’t need direct references to each other
Many implementations are provided by WPF
Delegate/Relay Commands
Initially put forth by Josh Smith
Encapsulates ICommand interface implementation
Works by passing delegates in the ViewModel
![Page 18: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/18.jpg)
RELAYCOMMANDSpublic class RelayCommand : ICommand {
private readonly Action _execute; private readonly Func<bool> _canExecute; public RelayCommand(Action execute) : this(execute, null) { } public RelayCommand(Action execute, Func<bool> canExecute) {
if (execute == null) throw new ArgumentNullException("execute");
_execute = execute; _canExecute = canExecute;
} public bool CanExecute(object parameter) {
return _canExecute == null || _canExecute(); } public void Execute(object parameter) {
_execute(); } public event EventHandler CanExecuteChanged{
add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; }
} }
public class RelayCommand<T> : ICommand {
private readonly Action<T> _execute; private readonly Func<T, bool> _canExecute; public RelayCommand(Action<T> execute) : this(execute, null) { } public RelayCommand(Action<T> execute, Func<T, bool> canExecute) {
if (execute == null) throw new ArgumentNullException("execute");
_execute = execute; _canExecute = canExecute;
} public bool CanExecute(object parameter) {
return _canExecute == null || _canExecute((T)parameter); } public void Execute(object parameter) {
_execute((T)parameter); } public event EventHandler CanExecuteChanged{
add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; }
} }
![Page 19: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/19.jpg)
VALUE CONVERTERS\COMMAND PARAMETERS
![Page 20: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/20.jpg)
VALUE CONVERTERS
public class LoginMultiConverter : IMultiValueConverter{
public object Convert( object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
var param = new LoginParameter(); //Omitted for brevity return param;
}
public object[] ConvertBack(object value, Type[] targetTypes,object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException(); }
}
![Page 21: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/21.jpg)
PASSING IN PARAMETERS
<Button Command="{Binding Path=LoginCmd}"><Button.CommandParameter>
<MultiBindingConverter="{StaticResource LoginMultiConverter}">
<MultiBinding.Bindings><Binding Path="UserName" /><Binding Path="Password" /><Binding ElementName="pgLogin" />
</MultiBinding.Bindings></MultiBinding>
</Button.CommandParameter></Button>
![Page 22: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/22.jpg)
The Command Pattern
![Page 23: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/23.jpg)
OBSERVABLES
![Page 24: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/24.jpg)
OBSERVABLES
Models
Leverage INotifyPropertyChanged
Beware of magic strings
Collections
Leverage ObservableCollections
Implements
INotifyCollectionChanged
INotifyPropertyChanged
![Page 25: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/25.jpg)
INOTIFYPROPERTYCHANGED (PRIOR TO 4.5)public class Product : INotifyPropertyChanged{
private string _modelName; public string ModelName{
get { return _modelName; } set{
if (_modelName == value) return; _modelName = value; onPropertyChanged(FieldNames.ModelName);
} } public bool IsDirty { get; set; }
public event PropertyChangedEventHandler PropertyChanged; private void onPropertyChanged(Enum fieldName) {
IsDirty = true; if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(string.Empty)); //PropertyChanged(this, new PropertyChangedEventArgs(fieldName.ToString()));
}
} }
![Page 26: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/26.jpg)
INOTIFYPROPERTYCHANGED (4.5+)public class Product : INotifyPropertyChanged{
private string _modelName; public string ModelName{
get { return _modelName; } set{
if (_modelName == value) return; _modelName = value; OnPropertyChanged();
} }
public event PropertyChangedEventHandler PropertyChanged; private void onPropertyChanged([CallerMemberName]string fieldname = "") {
if (fieldname != "IsDirty") IsDirty = true; if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(string.Empty)); //PropertyChanged(this, new PropertyChangedEventArgs(fieldName));
}
} }
![Page 27: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/27.jpg)
OBSERVABLECOLLECTIONS – THE HARD WAYpublic class ProductList : IProductList{
private readonly IList<Product> _products; public ProductList(IList<Product> products) {
_products = products; } public void Add(Product item) {
_products.Add(item); notifyCollectionChanged(new
NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } public void Clear() {
_products.Clear(); notifyCollectionChanged(new
NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } //Ommitted for brevitypublic event NotifyCollectionChangedEventHandler CollectionChanged; private void notifyCollectionChanged(NotifyCollectionChangedEventArgs args) {
if (CollectionChanged != null) {
CollectionChanged(this, args); }
} }
![Page 28: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/28.jpg)
OBSERVABLECOLLECTIONS – THE EASY WAY
Products = newObservableCollection<Product>(newProductService().GetProducts());
Use the built in
ObservableCollection class
Constructor takes an
IEnumerable
![Page 29: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/29.jpg)
NOTIFYPROPERTYCHANGED – THE EASY WAY[ImplementPropertyChanged] public abstract class ModelBase :
INotifyDataErrorInfo, IDataErrorInfo{
public bool IsChanged { get; set; }// Omitted for brevity
}
public partial class Product : ModelBase{ }public partial class Product{
public int ID { get; set; } public string ModelName { get; set; } public string SKU { get; set; } public decimal Price { get; set; } public decimal SalePrice { get; set; } public int Inventory { get; set; }
}
Add PropertyChanged.Fody
INotifyPropertyChanged is
implemented for you
Add IsChanged for dirty tracking
![Page 30: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/30.jpg)
WHERE TO IMPLEMENT NOTIFICATIONS?
Anemic Model
Implemented in ViewModel
“Cleaner” model
Lots of code duplication
Anemic ViewModel
Implemented in Model
Less code duplication
Mixing of concerns?
In general – do what makes sense
![Page 31: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/31.jpg)
Observables
![Page 32: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/32.jpg)
VALIDATION
![Page 33: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/33.jpg)
VALIDATION METHODS
Raise an error on your data object
Use INotifyDataErrorInfo and/or IDataErrorInfo
INotifyDataErrorInfo is new in WPF 4.5
Define validation at the binding level
Note: Validation only occurs with TwoWay or OneWayToSource binding
modes
![Page 34: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/34.jpg)
VALIDATESONEXCEPTION
Raises exceptions from bound property
Reminder: Errors are ignored on bindings, user won’t know the issue
Sets Validation.HasError = True
Creates ValidationError object
If NotifyOnValidationError = true in binding
WPF raises Validation.Error
![Page 35: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/35.jpg)
CUSTOM VALIDATION RULES
Derive from ValidationRule
Add additional properties for custom configuration
Override Validate()
Return new ValidationResult(true || false, [Error Message])
Add to Binding.ValidationRules collection
![Page 36: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/36.jpg)
IDATAERRORINFO
Adds an string indexer for the model
Error property is not used by WPF
Relies on INotifyPropertyChanged to fire
Requires ValidatesOnDataErrors to binding statement
![Page 37: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/37.jpg)
IMPLEMENTING IDATAERRORINFOpublic class Product : IDataErrorInfo
{ public string this[string columnName]
{ get
{ var field = (FieldNames)Enum.Parse(typeof(FieldNames), columnName); switch (field) {
case FieldNames.Inventory: if (Inventory < 0) { return "Inventory can not be less than zero";} break;
case FieldNames.Price: if (Price < 0) {return "Price can not be less than zero";} break;
} return string.Empty;
}
} public string Error { get { throw new NotImplementedException();} }
}
![Page 38: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/38.jpg)
INOTIFYDATAERRORINFO
New in WPF 4.5
Contains
ErrorsChanged event
HasError Boolean
GetErrors() method to return the errors
Relies on INotifyPropertyChanged
ValidatesOnNotifyDataErrors is optional (set to true by default)
![Page 39: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/39.jpg)
IMPLEMENTING INOTIFYDATAERRORINFO
private Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public bool HasErrors { get { return (errors.Count > 0); } }
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName)) { return errors.Values; }
else
{
if (errors.ContainsKey(propertyName)) { return (errors[propertyName]); }
else { return null; }
}
}
private void RaiseErrorsChanged(string propertyName)
{
if (ErrorsChanged != null) {
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
![Page 40: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/40.jpg)
THE SUPPORT CODE
private void SetErrors(List<string> propertyErrors, [CallerMemberName]string propertyName = "")
{
errors.Remove(propertyName);
errors.Add(propertyName, propertyErrors);
RaiseErrorsChanged(propertyName);
}
private void AddError(string error, [CallerMemberName]string propertyName = "")
{
if (!errors.ContainsKey(propertyName)) { errors.Add(propertyName, new List<string>()); }
if (!errors[propertyName].Contains(error))
{
errors[propertyName].Add(error);
RaiseErrorsChanged(propertyName);
}
}
private void ClearErrors([CallerMemberName]string propertyName = "")
{
errors.Remove(propertyName);
RaiseErrorsChanged(propertyName);
}
![Page 41: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/41.jpg)
INOTIFYDATAERRORINFO VALIDATION IN THE SETTER
public decimal Price
{
//Getter Omitted
set
{
if (_price == value)
return;
_price = value;
if (Price < 0)
{
var errors = new List<string>() { "Price can not be less than zero" };
SetErrors(errors);
}
else
{
ClearErrors();
}
OnPropertyChanged();
}
}
![Page 42: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/42.jpg)
USING IDATAERRORINFO AND INOTIFYDATAERRORINFO
Enables validation in generated code
Use string indexer to call validation code
Requires ValidatesOnDataErrors in binding statement
ValidatesOnNotifyDataErrors is optional (set to true by default)
![Page 43: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/43.jpg)
INOTIFYDATAERRORINFO AND IDATAERRORINFOpublic string this[string columnName]
{
get
{
var field = (FieldNames)Enum.Parse(typeof(FieldNames), columnName);
switch (field)
{
case FieldNames.Inventory:
ClearErrors(columnName);
CheckSalePrice(columnName);
if (Inventory < 0) { AddError("Inventory can not be less than zero", columnName); }
CheckSalePrice(FieldNames.SalePrice.ToString());
break;
case FieldNames.SalePrice:
ClearErrors(columnName);
CheckSalePrice(columnName);
if (SalePrice < 0) { AddError("Sale Price can not be less than zero", columnName); }
CheckSalePrice(FieldNames.Inventory.ToString());
break;
default:
break;
}
return string.Empty;
}
}
![Page 44: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/44.jpg)
ADDING VALIDATION RESULTS TO UI
![Page 45: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/45.jpg)
LEVERAGING VALIDATION IN XAML
<TextBox Text="{Binding ElementName=ProductSelector, Path=SelectedItem.ModelName, ValidatesOnExceptions=true, ValidatesOnDataErrors=true}" />
<Style.Triggers><Trigger Property="Validation.HasError" Value="true">
<Setter Property="Background" Value="Pink" /><Setter Property="Foreground" Value="Black" />
</Trigger></Style.Triggers><Setter Property="Validation.ErrorTemplate">
<Setter.Value><ControlTemplate>
<! Omitted for brevity --></ControlTemplate>
</Setter.Value></Setter>
![Page 46: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/46.jpg)
Validation
![Page 47: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/47.jpg)
BEHAVIORS
![Page 48: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/48.jpg)
BEHAVIORS
Introduced in Expression Blend v3
Encapsulate functionality into reusable components
Drag & Drop
Pan and Zoom
Input Validation
Watermark Text
InvokeCommand
Additional Behaviors are available from the Expression Gallery
http://msdn.microsoft.com/en-us/expression/jj873995
![Page 49: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/49.jpg)
Behaviors
![Page 50: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/50.jpg)
UI INTERACTION
![Page 51: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/51.jpg)
CHALLENGES
Challenges
Must keep separation of concerns
Must still be testable
One suggestion
Create Interfaces representing UI
Code to Interface instead of element
Another suggestion:
Create notification system
More complicated, more powerful
![Page 52: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/52.jpg)
CREATE AND LEVERAGE INTERFACES
public interface IAnimationController {
void StartAnimation(); void EndAnimation();
}
public override void Execute(object parameter) {
_param = parameter as LoginParameter; if (_param == null) { return;} _param.AnimationController.StartAnimation(); _bgw.RunWorkerAsync(_param);
}
![Page 53: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/53.jpg)
UI Interaction
![Page 54: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/54.jpg)
Models
The data of the application
(Can be) optimized for storage
Views
Accepts interactions from user
Returns results of interactions
ViewModel – Job 1
Façade for individual models
Transport mechanism for models
ViewModel – Job 2
Process incoming requests
Perform changes to the model
MVVM DECONSTRUCTED
![Page 55: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/55.jpg)
Questions?
![Page 56: MODEL-VIEW-VIEWMODEL FOR WPFIMPLEMENTING ICOMMAND BY HAND-WPF public class DoSomethingCommand : CommandBase { public DoSomethingCommand() { //do something if necessary } public override](https://reader030.fdocuments.us/reader030/viewer/2022040602/5e96959b4406996e1e5318b9/html5/thumbnails/56.jpg)
www.sds-consulting.com
www.skimedic.com/blog
www.twitter.com/skimedic
www.hallwayconversations.com
www.about.me/skimedic
Contact Me