Change Dependency Property value on Textbox ValidationRule - wpf

I have implemented Custom Control inheriting from ContentControl,which has dependency property called "CanNavigate"(bool).
In a Window.xaml,I have a text box with some ValidationRule checking for Textbox emptiness.I want to set "CanNavigate" to true/false based on TextBox.Validation.HasError as shown below code:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="{Binding CanNavigate}" Value="false"></Setter>
</Trigger>
</Style.Triggers>
</Style>
Having this code,gives an error "'Property' property cannot use markup extensions or property element syntax on Setter. Only the Value property can use markup extensions or property element syntax. Error at object 'System.Windows.Setter' in markup file"
Is there a way where I can set CanNavigate property based on TextBox.validationError.
Regards,
Patil

Concerning your first setter I think you should replace this setter with a Binding on the ToolTip property and use a ValueConverter when neccessary, triggers can not.
It's better to do it like this (note I haven't tested this piece of code I'm just trying to point to this way):
<TextBox ... ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
Concerning the second setter: In a setter when defining the Property you don't need to specify a Binding you just provide the property name just like this:
<Setter Property="CanNavigate" Value="False" />

Related

Binding to attached property of property in style

Before I begin, my end goal here is to have a default ToolTip style for all controls which has a normal border that goes red when there's a validation error on the control for which the ToolTip is being shown.
So ToolTip has a PlacementTarget property which is the control over which the ToolTip is being shown. There is a Validation.HasError attached property that gets set on that PlacementTarget control when it has a databinding error. For instance I've got a TextBox, and in the TextBox style I can do this:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Content="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.(Validation.Errors)[0].ErrorContent}"/>
Now, I can just make a style for the ToolTip with a red border and set it in that trigger above, but I'd rather not have to do this in every control's style triggers, so I want my ToolTip style to handle this functionality itself if possible.
I've tried various things, most recently this (the converter basically returns red if there's an error, black if not):
<Style TargetType="{x:Type ToolTip}">
<Setter Property="BorderBrush" Value="{Binding Path=PlacementTarget.Validation.HasError, RelativeSource={RelativeSource Self}, Converter={StaticResource ToolTipBorderConverter}}"/>
</Style>
But from the error that gives it looks like that's trying to get an actual property called Validation on the TextBox, as opposed to the attached property:
System.Windows.Data Error: 40 : BindingExpression path error: 'Validation' property not found on 'object' ''TextBox' (Name='')'. BindingExpression:Path=PlacementTarget.Validation.HasError; DataItem='ToolTip' (Name=''); target element is 'ToolTip' (Name=''); target property is 'BorderBrush' (type 'Brush')
I also tried something like:
<Style TargetType="{x:Type ToolTip}">
<Style.Triggers>
<Trigger Property="PlacementTarget.Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red"/>
But I get an error saying I can't nest the Trigger's property like that.
Is there a way to accomplish what I'm trying to do here?
Searched for an answer for this for hours, and right after posting I saw a related article that got me the answer: you have to wrap Validation.HasError in parentheses for it to recognize it as an attached property.
<Style TargetType="{x:Type ToolTip}">
<Setter Property="BorderBrush" Value="{Binding Path=PlacementTarget.(Validation.HasError), RelativeSource={RelativeSource Self}, Converter={StaticResource ToolTipBorderConverter}}"/>

wpf datatrigger + value binding

I have a custom component that should change your alignment as a property of the window changes and getting the value of another property of itself. The property of the window is changing correctly, however, the alignment of the component is not changing. The converter that returns the alignment is also working correctly (it returns Left, Right or Center, depending on the other property of the component). So where is the error? Here is the code of the DataTrigger:
<myComponent.Resources>
<lib:HorizontalAlignmentConverter x:Key="HorizontalAlignmentConverter"/>
<Style TargetType="{x:Type myComponent}" x:Key="HorizontalAligner">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MainWindow1, Path=myWindowResizedProperty}" Value="True">
<Setter Property="HorizontalAlignment" Value="{Binding Path=myOtherProperty, RelativeSource={RelativeSource Self}, Converter={StaticResource HorizontalAlignmentConverter}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</myComponent.Resources>
Thanks in advance!
Another question: Is there any way I can reference, in the expression of DataTrigger Binding, the Window object, without using his name? This way would be more generic.
Thanks again!

How to set a viewmodel property if a listbox item selected?

I have a listbox...and it is bound to list of items of type (class) "A". Class "A" has a boolean property "IsCurrentViewActive". This is false by default. When user select an item in listbox....i need to set the "IsCurrentViewActive" property of corresponding item to TRUE.
I tried the below code in my listbox...but it is not working..Any help would be appreciated.
<Style x:Key="ListBoxItemTabStyle2Extended" TargetType="{x:Type ListBoxItem}" >
<Setter Property="IsSelected" Value="{Binding Path=IsCurrentViewActive, Mode=TwoWay}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Value="True">
<Setter Property="IsSelected" Value="{Binding Path=IsCurrentViewActive, Mode=TwoWay}"/>
</DataTrigger>
</Style.Triggers>
</Style>
EDIT : Can we do this way or Do I need to use attached property ?
The above XAML worked fine for me actually. I think it's just a matter of getting the context right. I have created a sample that you can download where this works fine. I think the difference might be that in my version, I store the style in ListBox's parent control's resources. I don't think you can store them in the ListBox's resources.
https://www.dropbox.com/s/s64kp9p0b2w1imk/ListBoxMenu.7z?dl=0

Updating style on runtime in wpf

I have a style for a ItemContainer that is based on the Item being contained (With a StyleSelector). It works fine. However on runtime the property might be changed but the style isn't updated instantly.
Is there anyway for me to get it to update as soon as the changes are saved?
Use a DataTrigger and a Converter which returns the Type of an object
For example,
<Style.Triggers>
<DataTrigger Binding="{Binding Converter=ObjectToTypeConverter}"
Value="{x:Type local:Person}">
<Setter Property="ItemTemplate" Value="{Binding PersonTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Converter=ObjectToTypeConverter}"
Value="{x:Type local:Business}">
<Setter Property="ItemTemplate" Value="{Binding BusinessTemplate}" />
</DataTrigger>
</Style.Triggers>
Use binding. Then you will need to implement INotifyPropertyChanged. The value you are setting should be a property and at the end of the setter, raise the property changed event.
If you give an example of your XAML, I can write it out for you.

WPF ComboBox - showing something different when no items are bound

I have a ComboBox, and i want to change its look when the ItemsSource property is null. When it is in that state, i want to show a TextPanel with the text "Retrieving data" in it, and give it a look kind of similar to the watermarked textbox.
I figure to do this i need a ControlTemplate, and a trigger. I have the ControlTemplate here:
<ControlTemplate x:Key="LoadingComboTemplate" TargetType="{x:Type ComboBox}">
<Grid>
<TextBlock x:Name="textBlock" Opacity="0.345" Text="Retrieving data..." Visibility="Hidden" />
</Grid>
<!--
<ControlTemplate.Triggers>
<Trigger Property="ComboBox.ItemsSource" Value="0">
<Setter Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
-->
</ControlTemplate>
but my issue is how do i set up the trigger to show this when the ItemsSource property is null? I have tried a couple of different ways, and each way has given me the error message "Value 'ItemsSource' cannot be assigned to property 'Property'. Invalid PropertyDescriptor value.". My ComboBox xaml is this (including the attempted trigger):
<ComboBox Margin="112,35,80,0"
Name="MyComboBox"
Height="22.723"
VerticalAlignment="Top"
DisplayMemberPath="FriendlyName"
SelectedValuePath="Path"
TabIndex="160"
>
<Trigger>
<Condition Property="ItemsSource" Value="0" />
<Setter Property="Template" Value="{StaticResource LoadingComboTemplate}" />
</Trigger>
</ComboBox>
now should the trigger go on the ComboBox, or on the ControlTemplate? How do i access the ComboBox's ItemsSource property? Should i even be using a trigger?
Thanks!
Try putting {x:Null} for the value of the condition instead of 0.
Also I got it working by moving the Trigger to a style and modifing it slightly, see below.
<Style TargetType="ComboBox" x:Key="LoadingComboStyle">
<Style.Triggers>
<Trigger Property="ItemsSource" Value="{x:Null}">
<Setter Property="Template" Value="{StaticResource LoadingComboTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
<ComboBox Style="{StaticResource LoadingComboStyle}" .... >
The reason it only works in a style, is that only EventTriggers are allowed in the triggers collection directly on the Framework Element. For property triggers (like above) you need to use a style (I learn something every day).
See FrameworkElement.Triggers
Note that the collection of triggers established on an element only supports EventTrigger, not property triggers (Trigger). If you require property triggers, you must place these within a style or template and then assign that style or template to the element either directly through the Style property, or indirectly through an implicit style reference.

Resources