rrn

I have an object with properties 'StartDate' and 'EndDate'. In my XAML, I have set a custom ValidationRule on the textbox binding to the 'EndDate' where it checks to see if the date falls in the range of 6 months to 2 years of the 'StartDate'. As shown in the xaml below, I have a property 'DateToCheckFrom' in my ValidationRule which needs to be bound to 'MyObject' property 'StartDate'. But doing the following gives me an error saying that I nee d to bind to a dependency property of a dependency Object .

How can I do this in xaml Will using mode "OneWayToSource' help If so, how do I use it

<TextBox DataContext="{StaticResource MyObject}" Name="EndDateData" Style="{StaticResource TextStyleInherited}" >

<TextBox.Text>

<Binding Path="EndDate" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"

Converter="{StaticResource CustomDateTimeConverter}" >

<Binding.ValidationRules>

<rn:MyDateRangeValidationRule DateToCheckFrom="{Binding Path=StartDate}" />

</Binding.ValidationRules>

</Binding>

</TextBox.Text>

</TextBox>



Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Drew Marsh

Hmmm... can you try explicitly setting the Source of the Binding on your validation rule to your object Like so:

Code Snippet

<rn:MyDateRangeValidationRule DateToCheckFrom="{Binding Source={StaticResource MyObject}, Path=StartDate}" />

I realize you have the DataContext set for the TextBox, but something tells me that's not carrying down to the Binding for some reason.

HTH,
Drew





Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Josh Smith

To bind a property it must be a dependency property. A dependency property can only exist on a subclass of DependencyObject, which ValidationRule is not. So, you can't bind your DateToCheckFrom property as is. What you can do, however, is create a simple class which derives from DependencyObject and exposes a dependency property: DateToCheckFrom. Then hang an instance of that class off your MyDateRangeValidationRule class as a public property. That will allow you to do the following:

Code Snippet

<m:MyDateRangeValidationRule>

<m:MyDateRangeValidationRule.ValidDateRange>

<m:DateRange DateToCheckFrom="{Binding Path=StartDate}" />

</m:MyDateRangeValidationRule.ValidDateRange>

</m:MyDateRangeValidationRule>

In that example, DateRange is the DependencyObject subclass. ValidDateRange is a normal CLR property of type DateRange, which is a member of the validation rule subclass.

For more info about WPF data binding, read this: http://www.codeproject.com/WPF/GuidedTourWPF_3.asp

HTH






Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Drew Marsh

Ahh, duh, right. Good catch Josh.



Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

rrn

Thank you for your responses.

Josh, I do realize the reason for the error I was getting but did not know a way to work around it. Your solution looks like the way to go. I'll definitely try it out today itself and shall let you know. Thank you so much. And yes, I have read your post in code-project and you have done a good job.





Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

rrn

Josh, I tried your approach and this is what I have

Code Snippet

namespace ValidationTest

{

public class LeaseDateValidationRule : ValidationRule

{

private DateTime _minDateTime;

private DateTime _maxDateTime;

private DateCheck _dateCheck;

public LeaseDateValidationRule()

{

_dateCheck = new DateCheck();

_minDateTime = _dateCheck.DateToCheckFrom.AddMonths(3);

_maxDateTime = _dateCheck.DateToCheckFrom.AddYears(2);

}

public DateCheck ValidDateRange

{

get

{

return _dateCheck;

}

set

{

_dateCheck = value;

_minDateTime = _dateCheck.DateToCheckFrom.AddMonths(3);

_maxDateTime = _dateCheck.DateToCheckFrom.AddYears(2);

}

}

public override ValidationResult Validate(object value, CultureInfo cultureInfo)

{

DateTime currentDateTime = new DateTime();

try

{

if (((string)value).Length > 0)

currentDateTime = DateTime.Parse((String)value);

}

catch (Exception e)

{

return new ValidationResult(false, "DateTime is not in right format " + e.Message);

}

if ((currentDateTime < _minDateTime) || (currentDateTime > _maxDateTime))

{

return new ValidationResult(false,

"Lease should be for a minimum of 3 months or maximum of 2 yrs. Please enter date in the range: " + _minDateTime.ToShortDateString() + " - " + _maxDateTime.ToShortDateString() + ".");

}

else

{

return new ValidationResult(true, null);

}

}

}

public class DateCheck : DependencyObject

{

public static readonly DependencyProperty _dateToCheckFromProperty = DependencyProperty.Register(

"DateToCheckFrom", typeof(DateTime), typeof(DateCheck), new PropertyMetadata(DateTime.Now));

public DateTime DateToCheckFrom

{

get

{

return (DateTime)GetValue(_dateToCheckFromProperty);

}

set

{

SetValue(_dateToCheckFromProperty, value);

}

}

}

}

Code Snippet

XAML

<TextBox Name="EndDateData" >

<TextBox.Text>

<Binding Path="EndDate" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"

Converter="{StaticResource CustomDateTimeConverter}">

<Binding.ValidationRules>

<rn:LeaseDateValidationRule.ValidDateRange>
<rn:DateCheck DateToCheckFrom="{Binding Path=StartDate}" />

</rn:LeaseDateValidationRule.ValidDateRange>

</Binding.ValidationRules>

</Binding>

</TextBox.Text>

</TextBox>

Now I get an error saying that 'LeaseDateValidationRule.ValidDateRange ' does not exist in XML namespace 'clr-namespace:ValidationTest. Am I missing something

  • Totally off context .. I have been trying to access your blogs in Infusion but looks like it does not work . How can I read your posts




Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Josh Smith

I guess the xaml should look like this:

Code Snippet
<Binding.ValidationRules>
<rn:LeaseDateValidationRule>
<rn:LeaseDateValidationRule.ValidDateRange>
<rn:DateCheck DateToCheckFrom="{Binding Path=StartDate}" />
<rn:LeaseDateValidationRule.ValidDateRange>
</rn:LeaseDateValidationRule>
</Binding.ValidationRules>

Infusion deleted my old blog and didn't bother to keep a backup or send me the old content.

Someone was kind enough to send me a big PDF doc with many of my old posts, and I've been slowly reposting them (http://www.codeproject.com/WPF/HiliteListViewItemsInWPF.asp and http://www.codeproject.com/useritems/CustomListBoxLayoutInWPF.asp)

It's a really time consuming task, so I haven't reposted too many of them yet. Maybe I should just make that PDF doc available on my blog...






Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

rrn

Thanks Josh .. of course my XAML was wrong .. so stupid that I missed it

I must also thank you for your posts at http://joshsmithonwpf.wordpress.com/. the posts have helped me so much especially your debugging tips (though I could not get Snoop working in my machine for some reason which I'm still disappointed about), accessing elements from templates/resourceDictionaries, etc, etc, etc. ( I can go on and on). Anyways .. thank you for your great work





Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

rrn

Josh, I'm having another problem here. For some reason the Binding is not working for DateToCheckFrom

Code Snippet

<rn:DateCheck DateToCheckFrom="{Binding Path=StartDate}" />

eventhough I have set the DataContext at the parent level as shown below

Code Snippet

<TextBox DataContext="{StaticResource myObject}" Style="{StaticResource TextStyleInherited}" >

<TextBox.Text>

<Binding Path="EndDate" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"

Converter="{StaticResource CustomDateTimeConverter}" >

<Binding.ValidationRules>

<rn:LeaseDateValidationRule>

<rn:LeaseDateValidationRule.ValidDateRange>

<rn:DateCheck DateToCheckFrom="{Binding Path=StartDate}" />

</rn:LeaseDateValidationRule.ValidDateRange>

</rn:LeaseDateValidationRule>

</Binding.ValidationRules>

</Binding>

</TextBox.Text>

</TextBox>

This works if I set the source as part of my binding for DateToCheckFrom as shown below

Code Snippet

TextBox Style="{StaticResource TextStyleInherited}" >

<TextBox.Text>

<Binding Path="EndDate" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"

Converter="{StaticResource CustomDateTimeConverter}" >

<Binding.ValidationRules>

<rn:LeaseDateValidationRule>

<rn:LeaseDateValidationRule.ValidDateRange>

<rn:DateCheck DateToCheckFrom="{Binding Source={StaticResource myObject},Path=StartDate}" />

</rn:LeaseDateValidationRule.ValidDateRange>

</rn:LeaseDateValidationRule>

</Binding.ValidationRules>

</Binding>

</TextBox.Text>

</TextBox>

Why is it behaving this way





Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Josh Smith

Oh, that makes sense. You need to explicitly set the DateToCheckFrom's Source because the DateCheck object is not in the logical tree. The DataContext is only inherited by objects in the logical tree, but the DateCheck object returned ValidDateRange is not in the tree (and it doesn't even have a DataContext property!).

Thanks for the kind feedback about my blog. I'm glad to help out.

BTW - if my posts have answered your question, please mark them as The Answer so that others will know this thread contains useful info. Thanks!






Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

rrn

I'll not be able to provide the source directly since this textbox is part of my datatemplate and this datatemplate is used by my contentControl where I provide the DataContext. Is there a work around for this Any ideas or am I pretty much stuck with this limitation

Sure, I'll mark it 'Answer' .. I was just waiting to get everything to work first before marking this as 'Answer'





Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Josh Smith

Off the top of my head I have two possible workarounds...

1) Create another dependency property on the DateCheck class, perhaps called DataContext, and then bind that to the DataContext of the TextBox (ex. {Binding ElementName="theNameOfTheTextBox", Path="DataContext"} ). Then set the Source of the DateToCheckFrom Binding to that property (and set the Binding's RelativeSource={xTongue Tiedtatic RelativeSource.Self} ).

2) Set the DateToCheckFrom Binding's ElementName to the name of the TextBox, and the Path to it's DataContext. Then assign that binding a value converter which takes in the data object and returns the value of property to bind to.

There might be another way, but those should both work.






Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Josh Smith

Here's an article I just posted which was inspired by this thread: http://www.codeproject.com/useritems/AttachingVirtualBranches.asp




Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

rrn

Thanks Josh for posting this article. I took a look at it and I think this virtual branching concept will be very helpful in many scenarios. The one scenario where I think this may not help is when you are using a Control on a Page and its template resides in a ResourceDictionary.

For example, I have a ContentControl in a Page and its template is defined in the ResourceDictionary. In this case the ValidationRule is applied inside your template (which is in the ResourceDictionary) but the DataContext is defined at the ContentControl level which resides within the Page. Since ResourceDictionary is a loose XAML, defining

<FrameworkElement x:Key="DataContextBridge" /> should happen within your ResourceDictionary which means there will be no way to refer to the DataContext defined within my Page as a result you cannot build this virtual bridge. Did I understand this right

- Rajani.





Re: Windows Presentation Foundation (WPF) Binding ValidationRule's property

Josh Smith

When all else fails in XAML, there must be a way to do it in code. Smile

By "loose XAML" I assume you mean a standalone xaml file which is loaded from disc at runtime. In that case you can use VisualTreeHelper (or perhaps LogicalTreeHelper) to find the first element created by the control template, after it has been applied to the ContentControl. If you put the DataContextBridge element in that element's Resources, then you should be able to call FindResource on it to get the bridge element. At that point you can bind to its DataContext and complete the bridge.

I haven't tested this scenario, but I'm sure there must be a way to do it. When I get some time I'll look into it.

If you come up with a solution, please post it here, or in a comment on the article's messageboard. Thanks!