Binding to Parent of Unknown Type - wpf

I have a style and template for a tooltip and would like to bind some of the content in the tooltip to the parent's error collection. I can get this to work by explicitly setting the AncestorType like in the code below, but I would like this to apply globally. I've tried using UIElement and FrameworkElement with no luck, but I think that's because it's not getting all of the way up the tree to find the correct element.
<ControlTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=(Validation.HasError)}"
Value="True">
<Setter
Property="Visibility"
TargetName="ErrorBorder"
Value="Visible" />
<Setter
Property="Text"
TargetName="ErrorText"
Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=(Validation.Errors)[0].ErrorContent}" />
</DataTrigger>
</ControlTemplate.Triggers>

Simple just try,
AncestorType=Control

You can use AncestorLevel in the RelativeSource.

I was able to get this working by binding to the PlacementTarget of the tooltip using the following binding:
{Binding RelativeSource={RelativeSource Mode=Self}, Path=PlacementTarget.(Validation.HasError)}"
This seems to be working well as long as the PlacementTarget for the tooltip is the control that has the error validation, which in my case it is.

Related

Get ValidationError in specific xaml element using a template

i have the following code snippet:
<ContentControl Height="16">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txtDistanceH, Path=(Validation.HasError)}" Value="True">
<Setter Property="Content" Value="{Binding ElementName=txtDistanceH, Path=(Validation.Errors)[0]}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Now i want to put the style in a separate file instead of inline. However i would like to be able to specify which element it should get the Validation.Errors from, so i can use a single template for several different controls.
Is there any way to tell the template where it should get the Validation.Errors from, OTHER than binding to an element by name?
I tried setting the ContentControls DataContext to the element txtDistanceH, but then i just get a binding error saying that the property cannot be found on the root-element.
thanks for taking the time to answer my question. I've tried it and it works!
However i do have a comment and another related question.
The code i have now is:
<!-- Set content of contentcontrol to the ValidationError of a control stored in Tag, if there is one -->
<Style x:Key="ShowValidationError" TargetType="ContentControl">
<Style.Resources>
<x:Static x:Key="EmptyString" Member="System:String.Empty" />
</Style.Resources>
<Setter Property="Content" Value="{StaticResource EmptyString}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag.(Validation.HasError)}" Value="True">
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource Self}, Path=Tag.(Validation.Errors).CurrentItem}" />
</DataTrigger>
</Style.Triggers>
</Style>
(Validation.Errors).CurrentItem is better than (Validation.Errors)[0], because the latter gives an out of range exception in the debug window when the error is resolved, see This Link for more information. The empty string ensures the control has the same size when its empty as when it has an error.
However even though it compiles and works, i still get some errors during design time. The code responsible is (Validation.HasError) and (Validation.Errors), respectively, in the above snippet.
Property 'Errors' is not attachable to elements of type 'Object'.
The property 'HasError' was not found in type 'Validation'.
Is there any way to fix / suppress these errors?
Bind the Tag property of the ContentControl to the target element using the element name binding and then update the style to use relative source self bindings to the tag to get at the validation errors.
Somewhere in Resources:
<Style x:Key=“ValidationStyle” TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag.(Validation.HasError)}" Value="True">
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource Self}, Path=Tag.(Validation.Errors)[0]}" />
</DataTrigger>
</Style.Triggers>
</Style>
And use it thusly:
<ContentControl Style=“{StaticResource ValidationStyle}” Tag=“{Binding ElementName=txtDistanceH}” />

How to bind property name to which column is binded to pass as command parameter

On each DataGridColumnHeader I have a button that I use to open a popup. As a parameter it sends the column's bound Property name to the ICommand in my ViewModel.
This works well for any DataGridTextColumn however when it comes to a DataGridComboBoxColumn the structure is different.
How would I solve this?
<Button Command="{Binding DataContext.OpenFilterCommand,
RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding Column.Binding.Path.Path,
RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
Problem Column Definition
<DataGridComboBoxColumn Header="Company" >
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CompanyCollection}"/>
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="SelectedValue" Value="{Binding Company}"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CompanyCollection}"/>
<Setter Property="SelectedValue" Value="{Binding Company}"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
Like I mentioned in previous question here that how to get value for DataGridTextColumn where i suggested to use Column.Binding.Path.Path to get bound property name.
But that won't work in this case since DataGridComboBoxColumn does not have any binding property. If syntax is like the one you mentioned in question above, you can get like this:
For SelectedValue i.e. Company:
<Button Command="{Binding DataContext.OpenFilterCommand,
RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding
Column.EditingElementStyle.Setters[1].Value.Path.Path,
RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
EXPLANATION
TemplatedParent (DataGridColumnHeader) --> Column (DataGridComboBoxColumn) --> EditingElementStyle(EditingElementStyle) --> Setters(1) (get first setter from style) --> Value (Setter Value) --> Path (PropertyPath) --> Path (Actual PropertyName)
If you want to get ItemsSource property name, replace Setters[1] with Setters[0].

How can I localize the value of boolean groupheaders in RadGridView

I have a telerik WPF RadGridView in which I have localized most text strings, but when grouping on a boolean field, it shows true/false, I want to localize these values as well, but I can't figure out how. See image below for an illustration.
To localize the other strings, I am using a resx file with the keys found at http://www.telerik.com/help/wpf/gridview-localization2.html.
edit: I have also set the Language property of the user control to the appropriate locale
I managed to solve this with a rather nasty workaround, so I'm still looking for a better solution, but if anyone needs this for the future, I solved it like this:
<telerik:GridViewCheckBoxColumn Header="{Binding Resx.Confirmed}" DataMemberBinding="{Binding Confirmed}">
<telerik:GridViewCheckBoxColumn.GroupHeaderTemplate>
<DataTemplate>
<Label>
<Label.Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Content" Value="{Binding DataContext.Resx.True, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Group.Items[0].Confirmed}" Value="False">
<Setter Property="Content" Value="{Binding DataContext.Resx.False, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</DataTemplate>
</telerik:GridViewCheckBoxColumn.GroupHeaderTemplate>
</telerik:GridViewCheckBoxColumn>

WPF RibbonButton: LargeImageSource and Label not updated via DataTriggers

I'm puzzled by a peculiar phenomenon in RibbonButton's behavior.
Everything works fine when I set the LargeImageSource and the Label statically in XAML:
<ribbon:RibbonButton x:Name="ButtonArchive"
LargeImageSource="..\Assets\archive_insert.png"
Label="{Binding Path=ItemArchiveButton,
Source={StaticResource Strings}}"/>
But when I try to modify these properties via DataTriggers - nothing seems to be happening.
The triggers do work; I can see the other properties - like Command or IsEnabled - set OK in the same trigger. It's just these too...
Here's the XAML:
<ribbon:RibbonButton x:Name="ButtonArchive"
LargeImageSource="..\Assets\archive_insert.png"
Label="{Binding Path=ItemArchiveButton, Source={StaticResource Strings}}">
<ribbon:RibbonButton.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding ="{Binding ElementName=ItemsList, Path=SelectedItem.IsArchived}" Value="false">
<Setter Property="ribbon:RibbonButton.Command" Value="{Binding ArchiveItemCommand}" />
<Setter Property="ribbon:RibbonButton.LargeImageSource" Value="..\Assets\archive_insert.png" />
<Setter Property="ribbon:RibbonButton.Label" Value="{Binding Path=ItemArchiveButton, Source={StaticResource Strings}}" />
</DataTrigger>
<DataTrigger Binding ="{Binding ElementName=ItemsList, Path=SelectedItem.IsArchived}" Value="true">
<Setter Property="ribbon:RibbonButton.Command" Value="{Binding RestoreItemCommand}" />
<Setter Property="ribbon:RibbonButton.LargeImageSource" Value="..\Assets\archive_extract.png" />
<Setter Property="ribbon:RibbonButton.Label" Value="{Binding Path=ItemRestoreButton, Source={StaticResource Strings}}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ribbon:RibbonButton.Style>
</ribbon:RibbonButton>
Setting the Command works fine in the both conditions, but not the other 2 properties...
Any advice will be welcome.
I asked the same question at the MSDN forum, and the answer I've got really solved this.
The problem is your setting properties for LargeImageSource and Label in the button itself. When you do this it takes precidence over your style triggers. I suggest using setters in the style to set your defaults, and remove the property settings it the button.

XAML Menuitem Visibility Bound to another control or trigger isn't working

Visibility="{Binding Path=Visibility, ElementName=btnUndo}"/>
I am trying to bind a menuitems visibility to another controls visibility (btnUndo).
That controls visibility is bound to a trigger
<Style x:Key="undoStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.isEdited, ElementName=lvBatches}" Value="True">
<Setter Property="FrameworkElement.Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItem.isEdited, ElementName=lvBatches}" Value="False">
<Setter Property="FrameworkElement.Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
I tried binding the MenuItem to the same trigger, but that didn't work either.
Any suggestions?
ContextMenus exist in the Adorner Layer, which is not the same Visual Tree as the UI layer.
I know you can bind something like the following in a MenuItem, which will return the Control the ContextMenu is attached to, and from there you might be able to find the data you're looking for.
{Binding Path=PlacementTarget, RelativeSource=
{RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}
For example, you could create a Converter which traverses up the VisualTree from the specified control until it finds the object it's looking for, or you could bind to the DataContext and look for a specific value within your ViewModel.

Resources