WPF databinding/validation for URIs? - wpf

My current setup binds the Text property of my TextBox to a certain Uri object. I'd love to use WPF's inbuilt validation to detect invalid URIs, and proceed from there. But this doesn't seem to be working?
I would imagine that it would throw an exception if I entered, e.g., "aaaa" as a URI. Thus, triggering my current setup, which is supposed to detect exceptions like so:
<TextBox Grid.Column="1" Name="txtHouseListFile" DockPanel.Dock="Right" Margin="3">
<TextBox.Text>
<Binding Source="{StaticResource Settings}" Path="Default.HouseListFile" Mode="TwoWay">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Then I would imagine I could check the various Validation properties, like so?
Validation.GetHasError(this.txtHouseListFile)
But, this appears to not work. Maybe it doesn't throw exceptions when trying to convert? Or maybe my setup's wrong? Corrections to either would be great.

You can try create our own ValidationRule (inherit from ValidationRule). In this class, override Validate(...) and try create an URI object and catch the exceptions. In the catch, just set the e.Message to exception message.
(I am not too sure what is your binding source. Is it a URI object or a string?)

OK, I think I know what is going on. The binding doesn't know how to convert a string to a URI object (because the textbox Text property is a string). You need a converter to help him.
Try this:
Create a converter class (inherit from IValueConverter) that:
convert a string to a Uri using the Uri constructor
convert a Uri to a string (using one of the multiple getters)
Put your converter in the Binding. Then, the converver will throw an exception in the Uri constructor and your ExceptionValidationRule will catch it.
Look here to know how to use a converter.

Related

I need an attached property to monitor parent for INotifyDataErrrorInfo

If I have the following binding
<TextBox Text="{Binding XXX.Name, ValidatesOnNotifyDataErrors=True}"/>
it doesn't work because only the DataContext implements INotifyDataErrorInfo and raises "XXX.Name" errors but ValidatesOnNotifyDataErrors tries to monitor XXX for error events not the data context.
However I am sure somebody could figure out how to write an attached property to do the following
<TextBox Grid.Column="5" Text="{Binding Binding.Name, c:ValidatesOnNotifyDataErrorsOnDataContext=True}"/>
where the data context is monitored not the child. Anybody got an idea how to start with that?
I think this is possible to implement, but because of the flexibility of bindings (RelativeSource, MultiBindings and whatnot) it would be difficult to make something like this that is truly robust. Personally, I think it would be cleaner to to implement INotifyDataErrorInfo at every level of the structure (and for parts of the structure that you don't own, like your Point example, use proxy classes that mirror the properties).
Anyway, Binding is a MarkupExtension, not a DependencyObject, which means attached properties can't be applied to it. You could inherit Binding to add your own properties, but this isn't very useful since it doesn't give you any overridable methods.
It shouldn't be necessary to extend Binding though, since all you want is a custom ValidationRule. Setting ValidatesOnNotifyDataErrors=True is equivalent to adding a NotifyDataErrorValidationRule:
<TextBox>
<TextBox.Text>
<Binding Path="XXX.Name">
<Binding.ValidationRules>
<NotifyDataErrorValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox>
</TextBox>
So you just need to replace NotifyDataErrorValidationRule with your own rule. If you override this Validate overload (which is passed the binding expression), you should be able to access the full binding path (through ParentBinding) and look up an error.

How to access converter from code in XAML?

I have a converter in the code behind called StringToIntConverter I try using it in xaml binding like this where s is the project namespace:
Converter={s:StringToIntConverter}
But it says that it is missing an assembly reference. What am I doing wrong?
I know there is some way to put it as a resource and then reference the resource but I am not sure how to do it.
<Some.Resources>
<s:StringToIntConverter x:Key="StringToIntConverter"/>
</Some.Resources>
<!-- ... -->
Converter={StaticResource StringToIntConverter}
Curly braces indicate a markup extension, they cannot just be used arbitrarily to instantiate objects, but for convenience you could turn your converter into a markup extension.
Something like:
public class StringToIntConverter : MarkupExtension, IValueConverter
{
//...
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
Then the code you used would work just fine!
Also note that you could use the binding in XML-element syntax to instantiate converters in place as well, e.g.
<TextBox>
<TextBox.Text>
<Binding Path="String">
<Binding.Converter>
<s:StringToIntConverter />
</Binding.Converter>
</Binding>
</TextBox.Text>
</TextBox>
Uhm - normally it goes something like this if I understand your question. You have created a converter right? In you XAML you need to add a reference to the assembly like this.
xmlns:converters="clr-namespace:Shared.Converters;assembly=Shared"
even if it is in the same assembly - something like...
xmlns:local="clr-namespace:ItemMaster"
Now you need to create a staticResource for whatever converter you want to use.
<converters:CostMethodToBooleanConverter x:Key="CostMethodToBooleanConverter"/>
Then you can use it.
IsEnabled="{Binding SelectedItem, Converter={StaticResource ReverseCostMethodToBooleanConverter}, ElementName=OemOriginalCostMethod}"/>
Does that help?

Add ValidationRules into a single xaml line OR shorthand ValidationRules

I'm using a PasswordBox which exposes a dependency property such that I can bind to it. The problem is that by using it like so, I cannot shorthand the Binding.ValidationRules to this syntax:
<PasswordBox services:RPLPasswordBoxBinder.BindPassword="True"
services:RPLPasswordBoxBinder.BoundPassword="{Binding Path=LoginUser.Parola, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</PasswordBox>
I set my ValidationRules to a textbox like this:
<TextBox.Text>
<Binding Path="LoginUser.Parola" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<some validation rule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
Is there any way to specify the ValidationRules collection to my PasswordBox in a single xaml line? Or maybe there's another clever solution for validating user input into my password box?
Some clarifications:
I'm using MVVM and I don't want to use code behind.
I want to add only a single ValidationRule. Maybe the problem with shorthanding Binding.ValidationRules is that this property is a collection. One validationrule would suffice in my situation.
There's a similar question on stackoverflow here. My problem is different as I don't just want to increase readability but actually validate my PasswordBox.
I suggest that you base your data model class on IDataErrorInfo and then validation is performed there and not in the code behind.
There are plenty of examples, but here's one for starters and another here.

wpf validation rules problem with textbox

I created a class IntegersValidationRule which inherits from ValidationRule. Now I don't know what code should I write in XAML. That's what I have:
<TextBox Name="defaultTxt"
Height="23" Width="200">
<TextBox.Text>
<Binding UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<what:IntegersValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
I know that either I'm so stupid that I can't understand in many tutorials what Path in Binding property means, why should we use Binding here when there's no binding required and what should I use instead of 'what' word inside Binding.ValidationRule.
what is an xmlns (see MSDN) which needs to point to the namespace in which your validation rule class is declared, e.g.
xmlns:what="clr-namespace:MyApp.MyValidationRules"
If you add no Path (- how about reading this if you do not understand it? -) the binding will bind to the current DataContext, whatever that may be in your case.
Question 1: validators work on bindings. That is why you specify the rule on a binding. As soon as then value will be updated to the source (object that the control binds to) the rule is checked.
Question 2: See H.B. 's answer

Can a WPF converter access the control to which it is bound?

Long version:
I have a simple WPF converter than does date conversions for me. The converter basically checks the date and formats it in dd/M/yyyy format. The converter does some smarts with the handling of the date which means that the user could type "23061971" and the value will be converted to "23/06/1971".
All this is trivial and working. The problem is that when I update the value, it does not update the caret position. Assume "|" is the caret and the user types "23061971|" then a millisecond later it is updated to "230619|71".
What I'd like to do is detect if the caret at the end of the value - if so, shift it to the end of the edit field once the new value has been updated. In order to do this, I'll need access to the edit control to which the converter is attached.
Short version:
From A WPF converter, can I get a reference to the control that is bound to that converter?
Here is an excellent article on how to get direct access to the control from within a converter: http://social.technet.microsoft.com/wiki/contents/articles/12423.wpfhowto-pass-and-use-a-control-in-it-s-own-valueconverter-for-convertconvertback.aspx
Essentially:
<MultiBinding Converter="{StaticResource MyConverter}" >
<Binding RelativeSource="{RelativeSource Self}" Mode="OneTime"/>
<Binding Path="MyValue2" />
</MultiBinding>
in the converter values[0] will be your control, ready for casting and values[1] would be the data that you are binding.
In a ValueConverter you can't get access to the control - however you can get access if you use a multibinding with a multivalueconverter.
In the multibinding the first binding is your binding as now - without the converter. The second binding you bind to the control itself - there you go acces to the control.
I have used this approach to gain other things also - you can make "dummy" bindings to properties you want to trigger updates, i.e. if you bind to the control itself you will only get updated if it changes, not if a property does - so create dummybindings for those.
You can send the control with the MultiBinding like this.
<TextBox Height="100" x:Name="textbox1" DockPanel.Dock="Top">
<TextBox.Text>
<MultiBinding Converter="{StaticResource MultiConverter}">
<Binding ElementName="textbox1" Path="." />
</MultiBinding>
</TextBox.Text>
</TextBox>
I don't thknk a converter has any way to get at the control that is using it. It is only a simple piece of logic that converts one object to another object.
However, in you case, perhaps you can trap the change event and then manually move the caret. If you think about it, caret position is strictly a view concern; it has nothing to do with converters or the data. You should not burden view-controller logic with it. You should definitely not burden converter logic (which is classified under utility classes) with it.

Resources