On my class I am implementing INotifyDataErrorInfo and it is working fine when validation error happens. It is putting that red frame around the TextBox, but it is not getting rid of it when validation error is fixed.
Here is my code:
string IDataErrorInfo.this[string columnName]
{
get
{
string error = null;
if (Context != null)
{
var messages = //GetMessages(); messages are validation errors
if (messages.Count != 0)
{
error = "This is critical error. Must be fixed";
AddError(columnName, "Some kind of error happend", false);
}
else
{
RemoveError(columnName);
}
}
return error;
}
}
//I call this method to check for validation errors.
public void CheckValidationErrors(string propertyName)
{
var error = this as IDataErrorInfo;
string message = error[propertyName];
}
private Dictionary<String, List<String>> errors =
new Dictionary<string, List<string>>();
public void AddError(string propertyName, string error, bool isWarning)
{
if (!errors.ContainsKey(propertyName))
errors[propertyName] = new List<string>();
if (!errors[propertyName].Contains(error))
{
if (isWarning) errors[propertyName].Add(error);
else errors[propertyName].Insert(0, error);
RaiseErrorsChanged(propertyName);
}
}
public void RemoveError(string propertyName, string error="")
{
if (error == "")
{
errors.Remove(propertyName);
RaiseErrorsChanged(propertyName);
}
else
{
if (errors.ContainsKey(propertyName) &&
errors[propertyName].Contains(error))
{
errors[propertyName].Remove(error);
if (errors[propertyName].Count == 0) errors.Remove(propertyName);
RaiseErrorsChanged(propertyName);
}
}
}
public void RaiseErrorsChanged(string propertyName)
{
if (ErrorsChanged != null)
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public System.Collections.IEnumerable GetErrors(string propertyName)
{
if (String.IsNullOrEmpty(propertyName) ||
!errors.ContainsKey(propertyName)) return null;
return errors[propertyName];
}
public bool HasErrors
{
get { return errors.Count > 0; }
}
I am calling RemoveError() method to remove errors.
Am I doing something wrong? When validation fixed I need to go to TextBox and tabbing of will take care of it. I want to remove that red frame right away when validation error is gone.
UPDATE:
When I type something to text box I need to send that info to the server asynchronously and response will bring me a message if there is any validation issues. So I can't do validation things on property changed. I will check for response if there any message added or removed. If any removed then I will call CheckValidationErrors().
ANSWER
I was implementing IDataErrorInfo and then decided to implement INotifyDataErrorInfo. I was thinking to make this validation work I need to implement both interfaces. So basically I removed IDataErrorInfo implementation from my class and that fixed the problem.
Thanks for the help!
Default value of UpdateSourceTrigger for TextBox is LostFocus.
You should change it to PropertyChanged if you want to run your validation logic right away once error is fixed.
<TextBox Text="{Binding PropertyName, UpdateSourceTrigger=PropertyChanged}"/>
I was implementing IDataErrorInfo and then decided to implement INotifyDataErrorInfo. I was thinking to make this validation work I need to implement both interfaces. So basically I removed IDataErrorInfo implementation from my class and that fixed the problem.
Related
I have a Car class.
class Car
{
string ModelNum;
}
Then I have Car instance
class CarInstance
{
string RegistrationNum;
}
There are several instances of Cars in my viewmodel.
ViewModel(Car car)
{
CarInstance Ins = car.GetInstance();
}
Question: Say that the Car itself is changing and it need to notify the view models of that change. What is the most efficient way to do this. I am aware I can use events(including eventaggregator in PRISM). I would like to know if there is any faster way to do this.
An Action parameter which can call multiple subscribers? Any such ideas?
All pseudocode.
Is INotifyPropertyChanged more performing than events?
The INotifyPropertyChanged interface defines a PropertyChanged event, i.e. it actually uses an event to notify the view.
Say that the Car itself is changing and it need to notify the view models of that change. What is the most efficient way to do this. I am aware I can use events(including eventaggregator in PRISM). I would like to know if there is any faster way to do this.
Raising an event will be very minor in terms of performance in most cases so you shouldn't worry about this:
How much performance overhead is there in using events?
The benefit of using an event aggregator is that your classes become more loosly coupled to each other compared to keeping a direct reference to each subscriber from each publisher class: https://blog.magnusmontin.net/2014/02/28/using-the-event-aggregator-pattern-to-communicate-between-view-models/
But raising an event, either using strong references or an event aggregator, is a good, recommended and fast way of notifying the outside world of a change.
Its absolute normal to put the property changed notifications in your models if they are bound to your views. It is the preferred approach over anything in MVVM. This is how you can do it
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public class Car: INotifyPropertyChanged
{
#region Property Changed
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private string _modelNum;
public string ModelNum
{
get{ return _modelNum; }
set
{
_modelNum = value;
//this will raise the notification
OnPropertyChanged("ModelNum");
}
}
}
If this car object is bound to your View, You can
Text="{Binding Car.ModelNum, UpdateSourceTrigger=PropertyChanged}"
UpdateSourceTrigger=PropertyChanged will update the UI whenever ModelName is updated or will update the ModelName whenever you update from UI.
Create the following class for notiyfing:
public abstract class Notifier : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
protected T Get<T>([CallerMemberName] string name = null)
{
Debug.Assert(name != null, "name != null");
object value = null;
if (_properties.TryGetValue(name, out value))
return value == null ? default(T) : (T)value;
return default(T);
}
protected void Set<T>(T value, [CallerMemberName] string name = null)
{
Debug.Assert(name != null, "name != null");
if (Equals(value, Get<T>(name)))
return;
_properties[name] = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public void Notify<T>(Expression<Func<T>> memberExpression)
{
if (memberExpression == null)
{
throw new ArgumentNullException("memberExpression");
}
var body = memberExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException("Lambda must return a property.");
}
var vmExpression = body.Expression as ConstantExpression;
if (vmExpression != null)
{
LambdaExpression lambda = Expression.Lambda(vmExpression);
Delegate vmFunc = lambda.Compile();
object sender = vmFunc.DynamicInvoke();
PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(body.Member.Name));
}
}
}
Your ViewModel should look something like this.
public class ViewModel : Notifier
{
public ObservableCollection<String> Messages
{
get { return Get<ObservableCollection<String>>(); }
set
{
Set(value);
Notify(() => AreThereMessages);
}
}
public bool AreThereMessages => Messages?.Count > 0;
}
You don't need any private variables with the Notifier class above.
Getter: get { return Get<T>(); }
Setter: get { Set(value); }
Notify other property: Notify(() => OtherProperty);
Example view:
<DataGrid ItemsSource="{Binding Messages}"/>
<Button IsEnabled="{Binding AreThereMessages}"/>
The code above notifies a button if the messages collection is empty or not.
This is the easiest way I know to handle your viewmodel without additional libraries.
Update the model from the view model
I have read some post about the MVVM but I not sure if understand the
way that the view model is updating the model
Currently I have two text boxes in the UI which is bound to the XAML view and call to the view model when the event was raised .
when should be the place in the view model when I updating the model?
This is the view model
class ViewModel:INotifyPropertyChanged
{
private String _url;
private String _TemplateType;
public string URL
{
get { return _url; }
set
{
if (value != _url)
{
_url= value;
OnPropertyChanged("URL");
}
}
}
public string TemplateType
{
get { return _TemplateType; }
set
{
if (value != _TemplateType)
{
_TemplateType= value;
OnPropertyChanged("URL");
}
}
}
The model
internal class DefineAddinModel
{
public string TemplateType { get; set; }
public String URL { get; set; }
}
The ViewModel usually acts as a wrapper around the Model and contains a reference to the Model which is can update either in response to commands or automatically in property setters.
UPDATE:
Here's an example of having the VM act as a wrapper around the Model. This may seem useless in your example but you will find in many cases the VM's getters/setters need to do some sort of transformation on the values rather than simply passing them through.
class ViewModel:INotifyPropertyChanged
{
private DefineAddinModel model;
public string URL
{
get { return model.URL; }
set
{
if (value != model.URL)
{
model.url = value;
OnPropertyChanged("URL");
}
}
}
public string TemplateType
{
get { return model.TemplateType; }
set
{
if (value != model.TemplateType)
{
model.TemplateType = value;
OnPropertyChanged("TemplateType");
}
}
}
The better way to update your Model Is by using an event, its safer, so choose weather using a button click or lost focus, or whatever you want
void button_click(object sender,eventsarg e)
{
MyObj.URL = App.Locator.MyVM.MyDefineAddinModel.URL;// App.Locator because MVVMLight is tagged
MyObj.TemplateType = App.Locator.MyVM.MyDefineAddinModel.TemplateType ;
}
but personnaly i Use the following steps :
1- In your ViewModel create a CurrentItem object of type DefineAddinModel and without OnPropertyChanged then bind it to the View(UI) DataContext of the RootElement on the View )
2- for the model I use the INotifyPropertyChanged for each propery
3- after binding the datacontext of your root element to the CurrentItem of your ViewModel then bind just URL and TemplateType properties to your Controls, so any thing changes on the textbox will update CurrentItem properties
you can also chose the type of the binding (On LostFocus, or OnPropertyChanged)
You need to bind your TextBoxes to the two properties URL and TemplateType.
Try to use Commands (in the ViewModel)instead of events (in The CodeBehind) since you are in MVVM.
For updating the model : use a button with it's Command property bound to OnSave just like this example:
private String _url;
private String _TemplateType;
private DefineAddinModel _defineAddin;
public DefineAddinModel DefineAddin
{
get {return _defineAddin;}
set
{
_defineAddin = value;
OnPropertyChanged("DefineAddin");
}
}
public string URL
{
get { return _url; }
set
{
if (value != _url)
{
_url= value;
OnPropertyChanged("URL");
}
}
}
public string TemplateType
{
get { return _TemplateType; }
set
{
if (value != _TemplateType)
{
_TemplateType= value;
OnPropertyChanged("URL");
}
}
}
public RelayCommand OnSaved
{
get;
set;
}
public ViewModel()
{
DefineAddin = new DefineAddinModel();
OnSaved = new RelayCommand(()=>
{
DefineAddin.URL = URL ;
DefineAddin.TemplateType = TemplateType;
});
Think about using third parties like MVVMLight it helps you a lot with MVVM and the helpers around it (Commands, Messenger, ViewModelLocator ...)
I think that the correct answer here is 'it depends'.
In most general cases, the advantage of actually using a ViewModel is also to track 'transient state', i.e. the state of an 'edit in progress' operation.
In this particular case, you would not push your changes directly to the Model every time a value is updated, instead you would do this via an 'Update' ICommand implementation that will collect all the data from the ViewModel and push it down to the Model.
This approach gives you many advantages:
The user of the view can change their mind as many times as they want, and only when they are happy will the Model actually get updated with their definitive choices
It greatly reduces the load on your persistence service, since only final changes are pushed through.
It allows you to do final validation on a complete set of values, rather than transient states, and hence reduces programming complexity and overhead.
It also makes your UI far more fluid since all the examples above are pushing updates on the UI Dispatcher, and avoids you having to cater for this via Tasks or other async approaches.
The backing model is never in an inconsistent state, since I would imagine that all values on one View/ViewModel are related, and only make sense when updated together using an ACID approach.
Here's an example of how I'd do it.
public class ViewModel:INotifyPropertyChanged {
private String _url;
private String _TemplateType;
public ViewModel(){
UpdateCommand = new DelegateCommand(OnExecuteUpdate, OnCanExecuteUpdate);
}
public bool OnCanExecuteUpdate(object param){
// insert logic here to return true when one can update
// or false when data is incomplete
}
public void OnExecuteUpdate(object param){
// insert logic here to update your model using data from the view model
}
public ICommand UpdateCommand { get; set;}
public string URL{
get { return _url; }
set {
if (value != _url) {
_url= value;
OnPropertyChanged("URL");
}
}
}
public string TemplateType {
get { return _TemplateType; }
set {
if (value != _TemplateType) {
_TemplateType= value;
OnPropertyChanged("TemplateType");
}
}
}
... etc.
}
public class DelegateCommand : ICommand {
Func<object, bool> canExecute;
Action<object> executeAction;
public DelegateCommand(Action<object> executeAction)
: this(executeAction, null) {}
public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute) {
if (executeAction == null) {
throw new ArgumentNullException("executeAction");
}
this.executeAction = executeAction;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter) {
bool result = true;
Func<object, bool> canExecuteHandler = this.canExecute;
if (canExecuteHandler != null) {
result = canExecuteHandler(parameter);
}
return result;
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged() {
EventHandler handler = this.CanExecuteChanged;
if (handler != null) {
handler(this, new EventArgs());
}
}
public void Execute(object parameter) {
this.executeAction(parameter);
}
}
I'm currently work with Entity Framework 5.0 and WinForms. What I'd like to do is set-up validation on my POCO classes so that when I databind them to form fields I'd like to display UI validation errors via an ErrorProvider. I have set up a base "ValidationEntity" class that implements the IDataErrorInfo interface with some simple validation methods for my child classes to call. For the most part, validating the field length, range, etc.. seem to be working fine displaying the errors to the user via the ErrorProvider.
However, I seem to have ran into an issue with the "ValidateRequiredField" method. If I have a class that has a non-nullable integer field and the user happens to remove this value on the form the ErrorProvider does show a message to the end-user, but the message is "Input string was not in a recognized format". Now I assume this is because the form, being bound to an integer field, is attempting to convert the empty text into an integer and a conversion error is occurring prior to the value being sent to the POCO class property. My question is, what would the best approach to solve this be?
I'm guessing that I may have to implement the Validating methods of the TextBox controls inside the form, catch the empty/null entry, and set the appropriate error message on the error provider. However, I was hoping on a way to let the class handle the empty/null value and set the error inside the POCO class so that it propagates to the UI. Originally I had thought of creating a custom TypeConverter (e.g. RequiredIntTypeConverter) but ran into issues since I'm inheriting from the ValidationEntity class and couldn't think of a good way of adding to the errors.
Below is a sample from the ValidationEntity class as well as a snippet from the Company class.
ValidationEntity.cs
public class ValidationEntity : IDataErrorInfo
{
private readonly Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
string IDataErrorInfo.Error
{
get { return string.Empty; }
}
string IDataErrorInfo.this[string propertyName]
{
get
{
return (!errors.ContainsKey(propertyName) ? null : String.Join(Environment.NewLine, errors[propertyName]));
}
}
public void AddError(string propertyName, string error, bool isWarning)
{
if (!errors.ContainsKey(propertyName))
{
errors[propertyName] = new List<string>();
}
if (!errors[propertyName].Contains(error))
{
if (isWarning)
{
errors[propertyName].Add(error);
}
else
{
errors[propertyName].Insert(0, error);
}
}
}
public void RemoveError(string propertyName, string error)
{
if (errors.ContainsKey(propertyName) &&
errors[propertyName].Contains(error))
{
errors[propertyName].Remove(error);
if (errors[propertyName].Count == 0)
{
errors.Remove(propertyName);
}
}
}
public void ValidateFieldLength(string propertyName, string value, int maxLength)
{
string errorMessage = string.Format("Text entered exceeds max length of {0} characters", maxLength);
if (value != null)
{
if (value.Length > maxLength)
{
if (!errors.ContainsKey(propertyName))
{
AddError(propertyName, errorMessage, false);
}
}
else
{
RemoveError(propertyName, errorMessage);
}
}
else
{
RemoveError(propertyName, errorMessage);
}
}
public void ValidateRequiredField(string propertyName, string value)
{
string errorMessage = string.Format("{0} is required.", propertyName);
if (string.IsNullOrWhiteSpace(value))
{
AddError(propertyName, errorMessage, false);
}
else
{
RemoveError(propertyName, errorMessage);
}
}
}
Company.cs
public class Company : ValidationEntity
{
private int companyID;
private string companyName;
public int CompanyID
{
get { return this.companyID; }
set
{
OnCompanyIdChanging(value.ToString());
this.companyID = value;
}
}
public string CompanyName
{
get { return this.companyName; }
set
{
OnCompanyNameChanging(value);
this.companyName = value;
}
}
private void OnCompanyIdChanging(string value)
{
ValidateRequiredField("CompanyID", value);
}
private void OnCompanyNameChanging(string value)
{
ValidateRequiredField("CompanyName", value);
ValidateFieldLength("CompanyName", value, 30);
}
}
Thank you for your assistance.
After doing some more research on this and testing out code samples I was able to find a solution to this particular item. A custom TypeConverter was needed for a non-nullable integer conversion. I was able to locate information here
and ended up with the following TypeConverter for testing a "Required Integer":
public class RequiredIntConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
[System.Diagnostics.DebuggerNonUserCode]
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
{
throw new ApplicationException("This field requires an integer value and cannot be blank.");
}
int result = 0;
if (!int.TryParse(value.ToString(), out result))
{
throw new ApplicationException("The value could not be parsed as a valid integer data type.");
}
else
{
return result;
}
}
}
When I initially tested the code from the link above my debugger kept breaking when I attempted to throw the ApplicationException. Thinking this was an error in my code I was confused on how to use the TypeConverter. However, I found the following post which describes how to suppress the debugger from breaking on a method.
I'm still a bit unsure on why it breaks on this ApplicationException and how the ErrorProvider knows to display the underlying exception. If anyone could point me to some additional resources on this it would be greatly appreciated.
Have a great day.
I am using:
if (string.IsNullOrEmpty(myHttpContext.Request.QueryString["code"]))
{
if (myHttpContext.Session == null || myHttpContext.Session["code"] == null)
{
OutputError("Code", "Invalid code.");
}
else
{
code = myHttpContext.Session["code"].ToString();
}
}
else
{
code = myHttpContext.Request.QueryString["code"];
myHttpContext.Session.Add("code", code);
}
However I keep getting the error:
Object reference not set to an instance of an object.
For:
myHttpContext.Session.Add("code", code);
All I want to do is set a simple session, someone please help this is driving me crazy.
Has your IHttpHandler (ashx) class implemented IRequireSessionState? Otherwise the Session object will not be accessible.
public class MyHandler : IHttpHandler, IRequireSessionState
{
public bool IsReusable { get { return false; } }
public void ProcessRequest(HttpContext ctx)
{
// your code here
}
}
You forgot if (myHttpContext != null)
However you might want to use the always-present context instead: HttpContext.Current
// if querystring parameter has a value
if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["code"]))
// then use its value
Same for Session (if it's present - see #davisleeps answer for that)
https://stackoverflow.com/a/8598088/179972
I believe you might want to try
myHttpContext.Session["code"] = code;
Situation: Many times with WPF, we use INotifyPropertyChanged and IDataErrorInfo to enable binding and validation on our data objects. I've got a lot of properties that look like this:
public SomeObject SomeData
{
get { return _SomeData; }
set { _SomeData = value; OnPropertyChanged("SomeData"); }
}
Of course, I have an appropriate overridden IDataErrorInfo.this[] in my class to do validation.
Question: In a binding situation, when does the validation code get executed? When is the property set? When is the setter code executed? What if the validation fails?
For example:
User enters new data.
Binding writes data to property.
Property set method is executed.
Binding checks this[] for validation.
If the data is invalid, the binding sets the property back to the old value.
Property set method is executed again.
This is important if you are adding "hooks" into the set method, like:
public string PathToFile
{
get { return _PathToFile; }
set
{
if (_PathToFile != value && // prevent unnecessary actions
OnPathToFileChanging(value)) // allow subclasses to do something or stop the setter
{
_PathToFile = value;
OnPathToFileChanged(); // allow subclasses to do something afterwards
OnPropertyChanged("PathToFile");
}
}
}
If you want fine-grained control over the timing of validation, you can have it:
private Dictionary<string, string> Errors = new Dictionary<string, string>();
private object _MyProperty;
public object MyProperty
{
get { return _MyProperty; }
set
{
Errors["MyProperty"] = null;
if (value == _MyProperty)
{
return;
}
ValidateMyProperty(value); // may set Errors["MyProperty"]
if (Errors["MyProperty"] == null)
{
_MyProperty = value;
OnPropertyChanged("MyProperty");
}
}
}
public string this[string propertyName]
{
return Errors[propertyName];
}
No matter when data error information is requested and who's requesting it, it always returns the property's validation status as of the last time something tried to set the property.
Note that if you work at it, you can encapsulate the logic thusly:
public object MyProperty
{
set { _MyProperty = Validate("MyProperty", value, _MyProperty); }
}
private Dictionary<string, Func<object, string>> ValidationFunctions;
private object Validate(string propertyName, object value, object field)
{
Errors[propertyName] = null;
if (value == field)
{
return;
}
if (!ValidationFunctions.ContainsKey(propertyName))
{
return value;
}
Errors[propertyName] = ValidationFunctions[propertyName](value);
return (Errors[propertyName] == null)
? value
: field;
}
}