wpf - Adding an ExceptionValidationRule to a Binding in code -
i have been developing errorprovider control inherits decorator. validates elements within control bound something. loops through every binding , within frameworkelement , adds exceptionvalidationrule dataerrorvalidation binding's validationrules.
this method work:
private sub applyvalidationrulestobindings() dim bindings dictionary(of frameworkelement, list(of binding)) = getbindings() each felement in bindings.keys dim knownbindings list(of binding) = bindings(felement) each knownbinding binding in knownbindings 'applying exception , data error validation rules' knownbinding.validationrules.add(new exceptionvalidationrule()) knownbinding.validationrules.add(new dataerrorvalidationrule()) next next end sub
apparently dataerrorvalidationrule applied binding, exceptionvalidationrule not.
does know why might case?
edit: ok, little more info on problem.
i've been reading tons of msdn documentation on validation , binding class. binding.updatesourceexceptionfilter property allows specify function handles exceptions occur on binding if exceptionvalidationrule has been associated binding.
i added method updatesourceexceptionfilter property , guess what! executed. but!! though returned exception, validationerror object not added validation.errors collection of bound element though msdn documentation said be...
i commented out code adds exceptionvalidationrule dynamically , manually added 1 binding in xaml so:
<textbox horizontalalignment="left" name="textbox1" verticalalignment="top" width="200"> <textbox.text> <binding path="name"> <binding.validationrules> <exceptionvalidationrule /> </binding.validationrules> </binding> </textbox.text> </textbox>
the updatesourceexception method executed (i didn't change it) , error added validation.errors msdn stated.
what curious whole thing fact exceptionvalidationrule in fact added binding when done through vb.net code (or else the updatesourceexception never have executed); however, validate.errors not updated error.
as stated earlier, dataerrorvalidationrule added binding , works properly...i'm having problems exceptionvalidationrule.
my solution:
it turns out had call bindingoperations.setbinding method binding , property apply validation rules binding. had no way of retrieving dependencyproperty element/binding in applyvalidationrulestobindings method moved code applied rules call method provided method retrieves of bindings recursively.
here solution:
''' <summary>' ''' gets , returns list of bindings. ' ''' </summary>' ''' <returns>a list of known bindings.</returns>' private function getbindings() dictionary(of frameworkelement, list(of binding)) if _bindings nothing orelse _bindings.count = 0 _bindings = new dictionary(of frameworkelement, list(of binding)) findbindingsrecursively(me.parent, addressof retrievebindings) end if return _bindings end function ''' <summary>' ''' recursively goes through control tree, looking bindings on current data context.' ''' </summary>' ''' <param name="element">the root element start searching at.</param>' ''' <param name="callbackdelegate">a delegate called when binding if found.</param>' private sub findbindingsrecursively(byval element dependencyobject, byval callbackdelegate foundbindingcallbackdelegate) ' see if should display errors on element' dim members memberinfo() = element.[gettype]().getmembers(bindingflags.[static] or bindingflags.[public] or bindingflags.flattenhierarchy) each member memberinfo in members dim dp dependencyproperty = nothing ' check see if field or property given dependency property' if member.membertype = membertypes.field dim field fieldinfo = directcast(member, fieldinfo) if gettype(dependencyproperty).isassignablefrom(field.fieldtype) dp = directcast(field.getvalue(element), dependencyproperty) end if elseif member.membertype = membertypes.[property] dim prop propertyinfo = directcast(member, propertyinfo) if gettype(dependencyproperty).isassignablefrom(prop.propertytype) dp = directcast(prop.getvalue(element, nothing), dependencyproperty) end if end if if dp isnot nothing ' have dependency property. ' 'checking if has binding , if so, checking if bound property interested in' dim bb binding = bindingoperations.getbinding(element, dp) if bb isnot nothing ' element has dependencyproperty know of bound property interested in. ' ' passing information call method caller can handle it.' if typeof element frameworkelement if me.datacontext isnot nothing andalso directcast(element, frameworkelement).datacontext isnot nothing callbackdelegate(directcast(element, frameworkelement), bb, dp) end if end if end if end if next 'recursing through child elements' if typeof element frameworkelement orelse typeof element frameworkcontentelement each childelement object in logicaltreehelper.getchildren(element) if typeof childelement dependencyobject findbindingsrecursively(directcast(childelement, dependencyobject), callbackdelegate) end if next end if end sub ''' <summary>' ''' called when recursively populating bindings dictionary frameworkelements(key) , corresponding list of bindings(value)' ''' </summary>' ''' <param name="element">the element binding belongs to</param>' ''' <param name="binding">the binding belongs element</param>' ''' <param name="dp">the dependencyproperty binding bound to</param>' ''' <remarks></remarks>' sub retrievebindings(byval element frameworkelement, byval binding binding, byval dp dependencyproperty) 'applying exception validation , data error validation rules binding' 'to ensure validation occurs element' if binding.validationrules.tolist.find(function(x) gettype(exceptionvalidationrule) (x.gettype)) nothing binding.validationrules.add(new exceptionvalidationrule()) binding.validationrules.add(new dataerrorvalidationrule()) binding.updatesourceexceptionfilter = new updatesourceexceptionfiltercallback(addressof returnexceptionhandler) 'resetting binding include validation rules added' bindingoperations.setbinding(element, dp, binding) end if ' remember bound element. used display error messages each property.' if _bindings.containskey(element) directcast(_bindings(element), list(of binding)).add(binding) else _bindings.add(element, new list(of binding)({binding})) end if end sub
thanks!
-frinny
i'm not following how code works can't modify binding after has been used, can't add validationrule
s existing binding. think you'll have copy binding, property property , add validationrule
s , set new copied binding bindingoperations.setbinding(...)
.
another approach may create own subclassed binding add validationrule
s directly e.g
public class exbinding : binding { public exbinding() { notifyonvalidationerror = true; validationrules.add(new exceptionvalidationrule()); validationrules.add(new dataerrorvalidationrule()); } }
useable like
<textbox text="{local:exbinding path=myproperty}"/>
update
i don't think understood answer. can't modify binding once in use you're trying won't work. here's c# sample app shows this. contains 3 textbox
s
- first
textbox
adds binding exceptionvalidationrule in xaml - second
textbox
adds binding in xaml , adds exceptionvalidationrule in loaded event - third
textbox
adds binding exceptionvalidationrule in loaded event
the exceptionvalidationrule work textbox
1 , 3 not 2. uploaded sample here: http://www.mediafire.com/?venm09dy66q4rmq
update 2
work if set binding again after you've added validation rule like
bindingexpression bindingexpression = textbox.getbindingexpression(textbox.textproperty); binding textbinding = bindingexpression.parentbinding; textbinding.validationrules.add(new exceptionvalidationrule()); // set binding again after `exceptionvalidationrule` has been added bindingoperations.setbinding(textbox, textbox.textproperty, textbinding);
i'm not sure how getbindings
method look, maybe add setbindings
method set bindings again , call method after you've added exceptionvalidationrule
s
Comments
Post a Comment