c# - Multiple validation errors with INotifyDataErrorInfo, old messages don't disappear -
in wpf project, i'm validating textbox input inotifydataerrorinfo implementation. multiple errors can occur.
when input causes multiple errors, validation errors displayed. however, when fix 1 error, validation message doesn't change, means false error messages shown. when fix errors message disappears.
is problem implementation, or wpf implementation re-fetch validation message if haserrors changed? stepping through debugger, however, can see geterrors , haserrors both called.
steps reproduce attached example:
- enter 333333. 2 validation messages shown.
- change leading 3 2. still, both validation messages shown, although first error has been fixed.
- change second 3 0. both messages disappear
- change second digit 3 again. second validation message shown.
- change leading digit 3 again. second validation message shown, although should display both.
and yes, example doesn't make sense, since rid of first check, since it's included in second check.
the view:
<window x:class="weirdvalidationtest.validationtestview" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:weirdvalidationtest" height="60" width="400"> <window.datacontext> <local:validationtestviewmodel /> </window.datacontext> <window.resources> <local:validationerrorstostringconverter x:key="valerrtostring" /> <controltemplate x:key="errortemplate"> <border borderbrush="red" borderthickness="1"> <stackpanel orientation="horizontal"> <adornedelementplaceholder /> <textblock text="{binding converter={staticresource valerrtostring}}" background="white" /> </stackpanel> </border> </controltemplate> </window.resources> <grid> <textbox maxlength="6" validation.errortemplate="{staticresource errortemplate}" text="{binding inputvalue, updatesourcetrigger=propertychanged}" horizontalalignment="left" verticalalignment="top" width="100" /> </grid> </window>
(code-behind simple initializecomponent call in constructor)
the viewmodel:
using system; using system.collections; using system.collections.generic; using system.componentmodel; using system.runtime.compilerservices; namespace weirdvalidationtest { internal class validationtestviewmodel : inotifypropertychanged, inotifydataerrorinfo { private readonly dictionary<string, list<string>> errors = new dictionary<string, list<string>>(); private uint inputvalue; public event propertychangedeventhandler propertychanged; public event eventhandler<dataerrorschangedeventargs> errorschanged; public uint inputvalue { { return inputvalue; } set { if (inputvalue != value) { if (value / 100000 == 2) { removeerror("inputvalue", string.format("must in range {0}...{1}", "200000", "299999")); } else { adderror("inputvalue", string.format("must in range {0}...{1}", "200000", "299999")); } uint testnumber = (uint) ((value) / 1e4); { string msg = string.format("must start value {0}", "20...."); if (testnumber != 20) { adderror("inputvalue", msg); } else { removeerror("inputvalue", msg); } } inputvalue = value; onpropertychanged(); } } } public bool haserrors { { return errors.count != 0; } } public ienumerable geterrors(string propertyname) { list<string> val; errors.trygetvalue(propertyname, out val); return val; } void adderror(string propertyname, string messagetext) { list<string> errlist; if (errors.trygetvalue(propertyname, out errlist)) { if (!errlist.contains(messagetext)) { errlist.add(messagetext); } } else { errlist = new list<string> { messagetext }; errors.add(propertyname, errlist); } onerrorschanged(propertyname); } void removeerror(string propertyname, string messagetext) { list<string> errlist; if (errors.trygetvalue(propertyname, out errlist)) { errlist.remove(messagetext); if (errlist.count == 0) { errors.remove(propertyname); } } onerrorschanged(propertyname); } private void onerrorschanged(string propertyname) { var handler = errorschanged; if (handler != null) { handler(this, new dataerrorschangedeventargs(propertyname)); } } private void onpropertychanged([callermembername] string propertyname = "") { var handler = propertychanged; if (handler != null) { handler(this, new propertychangedeventargs(propertyname)); } } } }
the converter:
using system; using system.collections.objectmodel; using system.globalization; using system.linq; using system.windows; using system.windows.controls; using system.windows.data; namespace weirdvalidationtest { [valueconversion(typeof(readonlyobservablecollection<validationerror>), typeof(string))] internal class validationerrorstostringconverter : ivalueconverter { public object convert(object value, type targettype, object parameter, cultureinfo culture) { var errorcollection = value readonlyobservablecollection<validationerror>; if (errorcollection == null) { return dependencyproperty.unsetvalue; } return string.join(", ", errorcollection.select(e => e.errorcontent.tostring())); } public object convertback(object value, type targettype, object parameter, cultureinfo culture) { throw new notimplementedexception(); } } }
target .net version 4.5
edit: hit similar problem idataerrorinfo
, see question: validation rule not updating correctly 2 validation rules changing converter helps
nice explanation , code looks pretty too. resolved issue in way hope it. change adderror , removeerror methods this,
void adderror(string propertyname, string messagetext) { list<string> errlist; if (errors.trygetvalue(propertyname, out errlist)) { if (!errlist.contains(messagetext)) { errlist.add(messagetext); errors.remove(propertyname); onerrorschanged(propertyname); if (errlist != null) errors.add(propertyname, errlist); } } else { errlist = new list<string> { messagetext }; errors.add(propertyname, errlist); onerrorschanged(propertyname); } } void removeerror(string propertyname, string messagetext) { list<string> errlist; if (errors.trygetvalue(propertyname, out errlist)) { errlist.remove(messagetext); errors.remove(propertyname); } onerrorschanged(propertyname); if (errlist != null) errors.add(propertyname, errlist); }
Comments
Post a Comment