Validating method arguments with Data Annotation attributes - silverlight

The "Silverlight Business Application" template bundled with VS2010 / Silverlight 4 uses DataAnnotations on method arguments in its domain service class, which are invoked automagically:
public CreateUserStatus CreateUser(RegistrationData user,
[Required(ErrorMessageResourceName = "ValidationErrorRequiredField", ErrorMessageResourceType = typeof(ValidationErrorResources))]
[RegularExpression("^.*[^a-zA-Z0-9].*$", ErrorMessageResourceName = "ValidationErrorBadPasswordStrength", ErrorMessageResourceType = typeof(ValidationErrorResources))]
[StringLength(50, MinimumLength = 7, ErrorMessageResourceName = "ValidationErrorBadPasswordLength", ErrorMessageResourceType = typeof(ValidationErrorResources))]
string password)
{ /* do something */ }
If I need to implement this in my POCO class methods, how do I get the framework to invoke the validations OR how do I invoke the validation on all the arguments imperatively (using Validator or otherwise?).

We have approached it like this:
We have a ValidationProperty class that takes in a RegularExpression that will be used to validate the value (you could use whatever you wanted).
ValidationProperty.cs
public class ValidationProperty
{
#region Constructors
/// <summary>
/// Constructor for property with validation
/// </summary>
/// <param name="regularExpression"></param>
/// <param name="errorMessage"></param>
public ValidationProperty(string regularExpression, string errorMessage)
{
RegularExpression = regularExpression;
ErrorMessage = errorMessage;
IsValid = true;
}
#endregion
#region Properties
/// <summary>
/// Will be true if this property is currently valid
/// </summary>
public bool IsValid { get; private set; }
/// <summary>
/// The value of the Property.
/// </summary>
public object Value
{
get { return val; }
set
{
if (this.Validate(value))//if valid, set it
{
val = value;
}
else//not valid, throw exception
{
throw new ValidationException(ErrorMessage);
}
}
}
private object val;
/// <summary>
/// Holds the regular expression that will accept a vaild value
/// </summary>
public string RegularExpression { get; private set; }
/// <summary>
/// The error message that will be thrown if invalid
/// </summary>
public string ErrorMessage { get; private set; }
#endregion
#region Private Methods
private bool Validate(object myValue)
{
if (myValue != null)//Value has been set, validate it
{
this.IsValid = Regex.Match(myValue.ToString(), this.RegularExpression).Success;
}
else//still valid if it has not been set. Invalidation of items not set needs to be handled in the layer above this one.
{
this.IsValid = true;
}
return this.IsValid;
}
#endregion
}
Here's how we would create a Validation property. Notice how the public member is a string, but privately I am using a 'ValidationProperty.'
public string TaskNumber
{
get { return taskNumber.Value.ToString(); }
set
{
taskNumber.Value = value;
OnPropertyChanged("TaskNumber");
}
}
private ValidationProperty taskNumber;
Now, whenever the value is set, the business layer will validate that it's a valid value. If it's not, it will simply throw a new ValidationException (in the ValidationProperty class). In your xaml, you will need to set NotifyOnValidationError & ValidatesOnExceptions to true.
<TextBox Text="{Binding TaskNumber, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
With this approach, you would probably have a form for creating a new 'User' and each field would valitate each time they set it (I hope that makes sense).
This is the approach that we used to get the validation to be on the business layer. I'm not sure if this is exactly what you're looking for, but I hope it helps.

Related

How determine fault StoryBoard

The initial problem is enough known - "Cannot animate '(0).(1)' on an immutable object instance".
There are many questions here in SO about it but all the solutions are more fixes or crutches. And most of questions are linked to concrete part of code.
Also there are few topics about this problem with possible causes:
https://wpftutorial.net/DebuggingAnimations.html
https://blogs.msdn.microsoft.com/mikehillberg/2006/09/25/tip-cannot-animate-on-an-immutable-object-instance/
I have huge corporate app where a have hundreds styles and storyboards. I can't disable them step by step and it's painstaking work to looking for problem part of code.
I look at these bug not from side of looking for in many xamls but from side of loging. I tried to research info in InvalidOperationException that is raised but there is no useful info like control place in xaml or smth else.
Also one idea is to create class inherited from Storyboard and to override methods.
But there is no methods to override.
Can someone propose how to log the internality of storyboard or other class that is responsible of animation?
At last I found sulution.
You should add classes: listener to animation, AttachedProperty and custom StoryBoard.
public static class TriggerTracing
{
static TriggerTracing()
{
// Initialise WPF Animation tracing and add a TriggerTraceListener
PresentationTraceSources.Refresh();
PresentationTraceSources.AnimationSource.Listeners.Clear();
PresentationTraceSources.AnimationSource.Listeners.Add(new TriggerTraceListener());
PresentationTraceSources.AnimationSource.Switch.Level = SourceLevels.All;
}
#region TriggerName attached property
/// <summary>
/// Gets the trigger name for the specified trigger. This will be used
/// to identify the trigger in the debug output.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <returns></returns>
public static string GetTriggerName(TriggerBase trigger)
{
return (string)trigger.GetValue(TriggerNameProperty);
}
/// <summary>
/// Sets the trigger name for the specified trigger. This will be used
/// to identify the trigger in the debug output.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <returns></returns>
public static void SetTriggerName(TriggerBase trigger, string value)
{
trigger.SetValue(TriggerNameProperty, value);
}
public static readonly DependencyProperty TriggerNameProperty =
DependencyProperty.RegisterAttached(
"TriggerName",
typeof(string),
typeof(TriggerTracing),
new UIPropertyMetadata(string.Empty));
#endregion
#region TraceEnabled attached property
/// <summary>
/// Gets a value indication whether trace is enabled for the specified trigger.
/// </summary>
/// <param name="trigger">The trigger.</param>
/// <returns></returns>
public static bool GetTraceEnabled(TriggerBase trigger)
{
return (bool)trigger.GetValue(TraceEnabledProperty);
}
/// <summary>
/// Sets a value specifying whether trace is enabled for the specified trigger
/// </summary>
/// <param name="trigger"></param>
/// <param name="value"></param>
public static void SetTraceEnabled(TriggerBase trigger, bool value)
{
trigger.SetValue(TraceEnabledProperty, value);
}
public static readonly DependencyProperty TraceEnabledProperty =
DependencyProperty.RegisterAttached(
"TraceEnabled",
typeof(bool),
typeof(TriggerTracing),
new UIPropertyMetadata(false, OnTraceEnabledChanged));
private static void OnTraceEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var triggerBase = d as EventTrigger;
if (triggerBase == null)
return;
if (!(e.NewValue is bool))
return;
if ((bool)e.NewValue)
{
// insert dummy story-boards which can later be traced using WPF animation tracing
var storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Enter);
triggerBase.Actions.Insert(0, new BeginStoryboard() { Storyboard = storyboard });
//storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Exit);
//triggerBase.ExitActions.Insert(0, new BeginStoryboard() { Storyboard = storyboard });
}
else
{
// remove the dummy storyboards
//foreach (TriggerActionCollection actionCollection in new[] { triggerBase.EnterActions, triggerBase.ExitActions })
foreach (TriggerActionCollection actionCollection in new[] { triggerBase.Actions })
{
foreach (TriggerAction triggerAction in actionCollection)
{
BeginStoryboard bsb = triggerAction as BeginStoryboard;
if (bsb != null && bsb.Storyboard != null && bsb.Storyboard is TriggerTraceStoryboard)
{
actionCollection.Remove(bsb);
break;
}
}
}
}
}
#endregion
private enum TriggerTraceStoryboardType
{
Enter, Exit
}
/// <summary>
/// A dummy storyboard for tracing purposes
/// </summary>
private class TriggerTraceStoryboard : Storyboard
{
public TriggerTraceStoryboardType StoryboardType { get; private set; }
public TriggerBase TriggerBase { get; private set; }
public TriggerTraceStoryboard(TriggerBase triggerBase, TriggerTraceStoryboardType storyboardType)
{
TriggerBase = triggerBase;
StoryboardType = storyboardType;
}
}
/// <summary>
/// A custom tracelistener.
/// </summary>
private class TriggerTraceListener : TraceListener
{
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
{
base.TraceEvent(eventCache, source, eventType, id, format, args);
if (format.StartsWith("Storyboard has begun;"))
{
TriggerTraceStoryboard storyboard = args[1] as TriggerTraceStoryboard;
if (storyboard != null)
{
// add a breakpoint here to see when your trigger has been
// entered or exited
// the element being acted upon
object targetElement = args[5];
// the namescope of the element being acted upon
INameScope namescope = (INameScope)args[7];
TriggerBase triggerBase = storyboard.TriggerBase;
string triggerName = GetTriggerName(storyboard.TriggerBase);
var str = "";
var element = targetElement as DependencyObject;
while (element != null)
{
str += element.ToString() + Environment.NewLine;
element = VisualTreeHelper.GetParent(element);
}
LoggingInfrastructure.DefaultLogger.Log(...);
}
}
}
public override void Write(string message)
{
}
public override void WriteLine(string message)
{
}
}
Then you could add property to xaml where you need:
<EventTrigger Ui:TriggerTracing.TriggerName="CopyTextBlockStyle PreviewMouseLeftButtonDown"
Ui:TriggerTracing.TraceEnabled="True" RoutedEvent="PreviewMouseLeftButtonDown">

MVVM bind RelayCommand CanExecute to a Property?

I have a Timer and three buttons to control it: Start, Stop, and Pause.
Each button is bound to a RelayCommand.
I have a TimerState property of type enum TimerState. (This is useful for setting various GUI elements.)
Is there a way to somehow bind the RelayCommands' CanExecute functionality to the TimerState property?
Currently, I have 3 methods that look like this:
private bool CanStartTimer()
{
return (TimerState == TimerState.Stopped || TimerState == TimerState.Paused);
}
In the TimerState setter, I call
StartTimerCmd.RaiseCanExecuteChanged();
Is there a better way bind the CanExecute state of the RelayCommands to a property like TimerState?
Thanks for any insight.
I've implemented a class to handle commands, actually it's based on DelegateCommand because i'm using PRISM but it could easily be changed to be used with RelayCommand or any other class implementing ICommand
It could have bugs, i've not yet fully tested it, however it works fine in my scenarios, here it is:
public class MyDelegateCommand<TViewModel> : DelegateCommand where TViewModel : INotifyPropertyChanged {
private List<string> _PropertiesToWatch;
public MyDelegateCommand(TViewModel viewModelInstance, Action executedMethod)
: base(executedMethod) {
}
public MyDelegateCommand(TViewModel viewModelInstance, Action executedMethod, Func<bool> canExecuteMethod)
: base(executedMethod, canExecuteMethod) {
}
/// <summary>
///
/// </summary>
/// <param name="viewModelInstance"></param>
/// <param name="executedMethod"></param>
/// <param name="selector"></param>
public MyDelegateCommand(TViewModel viewModelInstance, Action executedMethod, Func<bool> canExecuteMethod, Expression<Func<TViewModel, object>> propertiesToWatch)
: base(executedMethod, canExecuteMethod) {
_PropertiesToWatch = RegisterPropertiesWatcher(propertiesToWatch);
viewModelInstance.PropertyChanged += PropertyChangedHandler;
}
/// <summary>
/// handler that, everytime a monitored property changes, calls the RaiseCanExecuteChanged of the command
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyChangedHandler(object sender, PropertyChangedEventArgs e) {
if (_PropertiesToWatch.Contains(e.PropertyName)) {
this.OnCanExecuteChanged();
}
}
/// <summary>
/// giving an expression that identify a propriety or a list of properties, return the property names obtained from the expression
/// Examples on selector usage
/// proprietà singola:
/// entity => entity.PropertyName
/// proprietà multiple
/// entity => new { entity.PropertyName1, entity.PropertyName2 }
/// </summary>
/// <param name="selector"></param>
/// <returns></returns>
protected List<string> RegisterPropertiesWatcher(Expression<Func<TViewModel, object>> selector) {
List<string> properties = new List<string>();
System.Linq.Expressions.LambdaExpression lambda = (System.Linq.Expressions.LambdaExpression)selector;
if (lambda.Body is System.Linq.Expressions.MemberExpression) {
System.Linq.Expressions.MemberExpression memberExpression = (System.Linq.Expressions.MemberExpression)(lambda.Body);
properties.Add(memberExpression.Member.Name);
}
else if (lambda.Body is System.Linq.Expressions.UnaryExpression) {
System.Linq.Expressions.UnaryExpression unaryExpression = (System.Linq.Expressions.UnaryExpression)(lambda.Body);
properties.Add(((System.Linq.Expressions.MemberExpression)(unaryExpression.Operand)).Member.Name);
}
else if (lambda.Body.NodeType == ExpressionType.New) {
NewExpression newExp = (NewExpression)lambda.Body;
foreach (var argument in newExp.Arguments) {
if (argument is System.Linq.Expressions.MemberExpression) {
System.Linq.Expressions.MemberExpression mExp = (System.Linq.Expressions.MemberExpression)argument;
properties.Add(mExp.Member.Name);
}
else {
throw new SyntaxErrorException("Syntax Error, selector has to be an expression that returns a new object containing a list of properties, e.g.: s => new { s.Property1, s.Property2 }");
}
}
}
else {
throw new SyntaxErrorException("Syntax Error, selector has to be an expression that returns a new object containing a list of properties, e.g.: s => new { s.Property1, s.Property2 }");
}
return properties;
}
}
note that my solution implies that this command has to be wired with the viewmodel that handle it and the viewmodel has to implement the INotifyPropertyChanged interface.
first two constructor are there so the command is backward compatible with DelegateCommand but the 3rd is the important one, that accepts a linq expression to specify which property to monitor
the usage is pretty simple and easy to understand, let me write it here with methods but of course you can create your handler methods. Suppose you have have a ViewModel called MyViewModel with two properties (PropertyX and PropertyY) that rise the propertychanged event, and somewhere in it you create an instance of SaveCommand, it would look like this:
this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
//execute
() => {
Console.Write("EXECUTED");
},
//can execute
() => {
Console.Write("Checking Validity");
return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
},
//properties to watch
(p) => new { p.PropertyX, p.PropertyY }
);
maybe i'll create an article somewhere about this, but this snippet should be clear i hope
Fabio's answer works well. Here's a parameterized version for DelegateCommand<T>. (I've tightened up the code a little, too.)
public class DepedencyCommand<TViewModel, TArg> : DelegateCommand<TArg>
where TViewModel : INotifyPropertyChanged
{
private readonly List<string> _propertiesToWatch;
public DepedencyCommand(Action<TArg> executedMethod)
: base(executedMethod) { }
public DepedencyCommand(Action<TArg> executedMethod, Func<TArg, bool> canExecuteMethod)
: base(executedMethod, canExecuteMethod) { }
public DepedencyCommand(TViewModel viewModelInstance, Action<TArg> executedMethod, Func<TArg, bool> canExecuteMethod, Expression<Func<TViewModel, object>> propertiesToWatch)
: base(executedMethod, canExecuteMethod)
{
_propertiesToWatch = _RegisterPropertiesWatcher(propertiesToWatch);
viewModelInstance.PropertyChanged += PropertyChangedHandler;
}
/// <summary>
/// handler that, everytime a monitored property changes, calls the RaiseCanExecuteChanged of the command
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
if (_propertiesToWatch.Contains(e.PropertyName))
{
this.OnCanExecuteChanged();
}
}
/// <summary>
/// giving an expression that identify a propriety or a list of properties, return the property names obtained from the expression
/// Examples on selector usage
/// proprietà singola:
/// entity => entity.PropertyName
/// proprietà multiple
/// entity => new { entity.PropertyName1, entity.PropertyName2 }
/// </summary>
/// <param name="selector"></param>
/// <returns></returns>
private static List<string> _RegisterPropertiesWatcher(Expression<Func<TViewModel, object>> selector)
{
var properties = new List<string>();
LambdaExpression lambda = selector;
if (lambda.Body is MemberExpression)
{
var memberExpression = (MemberExpression)lambda.Body;
properties.Add(memberExpression.Member.Name);
}
else if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
properties.Add(((MemberExpression)unaryExpression.Operand).Member.Name);
}
else if (lambda.Body.NodeType == ExpressionType.New)
{
var newExp = (NewExpression)lambda.Body;
foreach (var argument in newExp.Arguments)
{
if (argument is MemberExpression)
{
MemberExpression mExp = (MemberExpression)argument;
properties.Add(mExp.Member.Name);
}
else
throw new SyntaxErrorException("Syntax Error, selector has to be an expression that returns a new object containing a list of properties, e.g.: s => new { s.Property1, s.Property2 }");
}
}
else
throw new SyntaxErrorException("Syntax Error, selector has to be an expression that returns a new object containing a list of properties, e.g.: s => new { s.Property1, s.Property2 }");
return properties;
}
}
There doesn't seem to be a better solution. I know what you mean, it seems inelegant but whatever lipstick you put on it, the onus is on the objects involved in the expression to notify the command.
If your condition is based purely on other notify properties you could add your own handler to PropertyChanged, that provides a bit of abstraction.
In this case, TimerState would be a VM property. Then you can a handler to your ViewModel.PropertyChanged event. You can then inspect the property name and update your CanExecute. This is still ugly, but at least you have all the garbage in one block.

Entity Framework 4 - Notification on Associations

I am facing a few difficulties with EF 4, foreign keys and INotifyPropertyChanged / the partial methods exposed for scalar properties.
I hope you can help me find the right way to do this.
Image I have a Customer entity with *..1 relationship with the Country entity.
Now, I'd obviously like to be able to do:
var customer = new Customer();
customer.Country = [...]
...but I don't necessarily need the CountryKey property.
I create a Association in EF with the correct cardinality in the .edmx designer. I choose not to "add foreign key properties" in the dialog.
This leaves me with a generated class without the partial OnCountryChanging and OnCountryChanged.
Next, I try to add the foreign key properties, and I now have a OnCountryKeyChanging and OnCountryKeyChanged.
However, the generated code looks like this:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int64 CountryKey
{
get
{
return _CountryKey;
}
set
{
OnCountryKeyChanging(value);
ReportPropertyChanging("CountryKey");
_CountryKey = StructuralObject.SetValidValue(value);
ReportPropertyChanged("CountryKey");
OnCountryKeyChanged();
}
}
private global::System.Int64 _CountryKey;
partial void OnCountryKeyChanging(global::System.Int64 value);
partial void OnCountryKeyChanged();
As you can see from the generated code, the PropertyChanged notification occurs with "CountryKey" instead of "Country". This makes data binding in WPF difficult.
My question is: how do I get around this?
Do I wrap my object in a ViewModel, listen to property changes and strip the "Key" part?
Do I modify the T4 template?
Or is there a third option I just can't see yet?
I'd greatly appreciate any suggestions here, as I am experimenting with WPF / EF without wrapping each Model property in a ViewModel.
The 'best practices' approach is to decorate your model in a viewmodel, exposing the model properties as required. You can create a generic ViewModel with some nifty work with dynamicobject, using perhaps a property mapping etc.
public class DynamicViewModel : DynamicObject, INotifyPropertyChanged, IDisposable
{
public event PropertyChangedEventHandler PropertyChanged;
private static readonly Dictionary<Type, Tuple<Dictionary<string, PropertyInfo>, Dictionary<string, string>>> typeDictionary = new Dictionary<Type, Tuple<Dictionary<string, PropertyInfo>, Dictionary<string, string>>>();
private readonly Dictionary<string, object> additionalProperties = new Dictionary<string, object>();
private readonly object underlyingObject;
public object UnderlyingObject
{
get
{
return underlyingObject;
}
}
private readonly Type type;
/// <summary>
/// constructor which takes a model for which it will be extensing its perceived properties
/// </summary>
/// <param name="underlyingObject">the underlying object</param>
public DynamicViewModel(IBindableRfqViewModel underlyingObject) : this(underlyingObject, new Dictionary<string, string>())
{
}
/// <summary>
/// constructor which takes a model for which it will be extensing its perceived properties as well as a property map
/// </summary>
/// <param name="underlyingObject">the underlying object</param>
/// <param name="propertyMap">a string/string dictionary, where the key is a property on the underlying object, and the value is the name of the dynamic property to be used as a binding target</param>
public DynamicViewModel(IBindableRfqViewModel underlyingObject, Dictionary<string, string> propertyMap)
{
this.underlyingObject = underlyingObject;
if (underlyingObject is INotifyPropertyChanged)
{
((INotifyPropertyChanged)underlyingObject).PropertyChanged += OnUnderlyingPropertyChanged;
}
type = underlyingObject.GetType();
if (typeDictionary.ContainsKey(type))
{
return;
}
lock (typeDictionary)
{
if (typeDictionary.ContainsKey(type))
{
return;
}
var forwardPropertyMap = propertyMap;
var typeProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToDictionary(p => p.Name, p => p);
typeDictionary.Add(type, Tuple.Create(typeProperties,forwardPropertyMap));
}
}
private void OnUnderlyingPropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.OnPropertyChanged(e.PropertyName);
}
private bool TryGetProperty(string name, out object result)
{
try
{
var propertyData = typeDictionary[type];
var modelProperty = name;
if (propertyData.Item2.ContainsKey(name))
{
modelProperty = propertyData.Item2[name];
}
if (propertyData.Item1.ContainsKey(modelProperty))
{
result = propertyData.Item1[modelProperty].GetValue(underlyingObject, null);
return true;
}
if (additionalProperties.ContainsKey(name))
{
result = additionalProperties[name];
return true;
}
result = null;
return true;
}
catch (Exception ex)
{
result = null;
return false;
}
}
/// <summary>
/// <see cref="DynamicObject.TryGetMember" />
/// </summary>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return this.TryGetProperty(binder.Name, out result);
}
/// <summary>
/// <see cref="DynamicObject.TryGetIndex" />
/// </summary>
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
return this.TryGetProperty(indexes[0].ToString(), out result);
}
private bool TrySetProperty(string name, object value)
{
try
{
var propertyData = typeDictionary[type];
var modelProperty = name;
if (propertyData.Item2.ContainsKey(name))
{
modelProperty = propertyData.Item2[name];
}
if (propertyData.Item1.ContainsKey(modelProperty))
{
propertyData.Item1[modelProperty].SetValue(underlyingObject, value, null);
}
else
{
if (!additionalProperties.ContainsKey(name))
{
additionalProperties.Add(name, new object());
}
additionalProperties[name] = value;
}
this.OnPropertyChanged(name);
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// <see cref="DynamicObject.TrySetMember" />
/// </summary>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
return this.TrySetProperty(binder.Name, value);
}
/// <summary>
/// <see cref="DynamicObject.TrySetIndex" />
/// </summary>
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
return indexes.Length == 0 || this.TrySetProperty(indexes[0].ToString(), value);
}
private void OnPropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propName));
}
}
/// <summary>
/// IDisposable implementation
/// </summary>
public void Dispose()
{
if (underlyingObject is INotifyPropertyChanged)
{
((INotifyPropertyChanged)underlyingObject).PropertyChanged -= OnUnderlyingPropertyChanged;
}
if (underlyingObject is IDisposable)
{
((IDisposable)underlyingObject).Dispose();
}
}
}

MVVM : how to pass parameter to ViewModel's constructor

I'm using L. Bugnion's MVVM Light Framework.
What are some of the recommended approaches to pass parameters such as Customer's ID to ViewModel's constructor?
Edit:
The parameter I need for each ViewModel is not something that is shared across models. it is something unique to each viewmodel instance.
//Create a container class to pass via messenger service
public class CarSelectedArgs
{
#region Declarations
public Car Car { get; set; }
#endregion
#region Constructor
public CarSelectedArgs(Car car)
{
Car = car;
}
#endregion
}
//example of view model sending message.
public class SendingViewModel : ViewModelBase
{
private Car _car;
public Car SelectedCar
{
get { return _car; }
set
{
_car = value;
if (value != null)
{
//messenger will notify all classes that have registered for a message of this type
Messenger.Default.Send(new CarSelectedArgs(value));
}
}
}
}
//Example of ViewModel registering to recieve a message
public class SampleViewModel : ViewModelBase
{
#region Constructor
public SampleViewModel()
{
Messenger.Default.Register<CarSelectedArgs>(this, OnCarSelected);
}
#endregion
#region LocalMethods
void OnCarSelected(CarSelectedArgs e)
{
var NewCar = e.Car;
}
#endregion
}
For me the whole point of using MVVM Light is to avoid injecting anything into the constructor of a View Model. MVVM Light provides a Messaging facility that allows you to send your parameters to a listener registered inside of the View Model.
For example, this is my View Model from my WordWalkingStick project using VSTO and WPF:
using System;
using System.Xml.Linq;
using GalaSoft.MvvmLight.Messaging;
namespace Songhay.Wpf.WordWalkingStick.ViewModels
{
using Songhay.Office2010.Word;
using Songhay.OpenXml;
using Songhay.OpenXml.Models;
using Songhay.Wpf.Mvvm;
using Songhay.Wpf.Mvvm.ViewModels;
/// <summary>
/// View Model for the default Client
/// </summary>
public class ClientViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the <see cref="ClientViewModel"/> class.
/// </summary>
public ClientViewModel()
{
if(base.IsInDesignMode)
{
#region
this._flatOpcSourceString = ApplicationUtility
.LoadResource(
new Uri("/Songhay.Wpf.WordWalkingStick;component/PackedFiles/FlatOpcToHtml.xml",
UriKind.Relative));
this._xhtmlSourceString = ApplicationUtility
.LoadResource(
new Uri("/Songhay.Wpf.WordWalkingStick;component/PackedFiles/FlatOpcToHtml.html",
UriKind.Relative));
#endregion
}
else
{
this._flatOpcSourceString = "Loading…";
this._xhtmlSourceString = "Loading…";
//Receive MvvmLight message:
Messenger.Default.Register(this,
new Action<GenericMessage<TransformationMessage>>(
message =>
{
var tempDocFolder =
Environment.ExpandEnvironmentVariables("%UserProfile%/Desktop/");
var inputPath = tempDocFolder + "temp.docx";
var outputPath = tempDocFolder + "temp.html";
var flatOpcDoc =
XDocument.Parse(message.Content.TransformationResult);
OpenXmlUtility.TransformFlatToOpc(flatOpcDoc, inputPath);
this.FlatOpcSourceString = flatOpcDoc.Root.ToString();
var settings = new SonghayHtmlConverterSettings()
{
PageTitle = "My Page Title " + DateTime.Now.ToString("U"),
UseEntityMap = false
};
OpenXmlUtility.WriteHtmlFile(inputPath, outputPath, settings);
var xhtmlDoc = XDocument.Load(outputPath);
this.XhtmlSourceString = xhtmlDoc.Root.ToString();
}));
}
}
/// <summary>
/// Gets or sets the flat opc source string.
/// </summary>
/// <value>The flat opc source string.</value>
public string FlatOpcSourceString
{
get
{
return _flatOpcSourceString;
}
set
{
_flatOpcSourceString = value;
base.RaisePropertyChanged("FlatOpcSourceString");
}
}
/// <summary>
/// Gets or sets the XHTML source string.
/// </summary>
/// <value>The XHTML source string.</value>
public string XhtmlSourceString
{
get
{
return _xhtmlSourceString;
}
set
{
_xhtmlSourceString = value;
base.RaisePropertyChanged("XhtmlSourceString");
}
}
string _flatOpcSourceString;
string _xhtmlSourceString;
}
}
You can see that MVVM Light is messaging (not injecting) values into the constructor (Messenger.Default.Register) with its Messenger.
Request anything you want, via injection, using interfaces.
If you have settings shared across models, instantiate a singleton containing the values and expose them via ISomethingProvider and ISomethingEditor interfaces.
Here is what I do:
ViewModel needs to show a car window with car id passed as parameter:
ViewModel -> message to codebehind for view to open window. Message sends id.
Essentially in code behind:
var vm = new viewmodel(id);
var view = new view();
view.datacontext = vm;
view.show();
my viewmodel has a constructor that takes in an id.
In the case of writing tests against the viewmodel I sometimes create an overload of the viewmodel constructor that takes an ISomething as a parameter. I have the default constructor call the second one with a default implementation of ISomething. In case of the test I call the constructor with a test implementation. I know it's not the best method, because it creates a dependency between the two classes... but sometimes you'll have to take the easy path...
public class SomeViewModel
{
private ISomething internalSomething;
public void SomeViewModel():this(new Something()){}
public void SomeViewModel(ISomething something)
{
this.internalSomething = something;
}
}
Update
Creating a view in xaml can be like this:
<UserControl xmlns="...."
xmlns:Example="SomeNamespace">
<UserControl.DataContext>
<Example:SomeViewModel />
</UserControl.DataContext>
<Grid>
...
</Grid>
</UserControl>

Object reference not set to an instance of an object in ViewModelLocator Mvvm Light

I have multiple viewModels in my application and am binding/used them in ViewModelLocator mvvm light. I have done button on one of my DailyActivities.xaml page. but when i clicked on it,it gives me error in ViewModelLocator like "Object reference not set to an instance of an object". and control comes to this line :
public static void ClearActivities()
{
_activities.Cleanup(); //Error here
_activities = null;
}
here is the code for DailyActivitiesViewModel in ViewModelLocator:
private static ActivitiesViewModel _activities;
public static ActivitiesViewModel ActivitiesStatic
{
get
{
if (_activities == null)
{
CreateActivities();
}
return _activities;
}
}
/// <summary>
/// Gets the ViewModelPropertyName property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public ActivitiesViewModel Activities
{
get
{
return ActivitiesStatic;
}
}
/// <summary>
/// Provides a deterministic way to delete the ViewModelPropertyName property.
/// </summary>
public static void ClearActivities()
{
_activities.Cleanup(); --Error here
_activities = null;
}
/// <summary>
/// Provides a deterministic way to create the ViewModelPropertyName property.
/// </summary>
public static void CreateActivities()
{
if (_activities == null)
{
_activities = new ActivitiesViewModel();
}
}
Kindly Suggest?
Thanks
You need to determine if the field exists before you can use it: It seems like if the field _activities is already null then no clean-up is required.
why not do something like
public static void ClearActivites()
{
if (null == _activities) return;
_activities.Cleanup();
_activities = null;
}

Resources