cannot set tooltip in style - wpf

I searched and find out I can't set the tooltip in setter.value directly (in a style.xaml file). However I can use static resource to set the tooltip.
My question is, since I need to supply dynamic text for the tooltip, I can't use static resource. How should I do that?
here is my example.
<Style x:Key="ErrorStyleRadius" TargetType="{x:Type FrameworkElement}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding (Validation.HasError), RelativeSource={RelativeSource Mode=Self}}" Value="True"/>
<Condition Binding="{Binding (Validation.Errors), RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource IsError}}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<Label Content="{Binding somePropertyHere}"/>
</ToolTip>
</Setter.Value>
</Setter>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorControlTemplateRadiusError}"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding (Validation.HasError), RelativeSource={RelativeSource Mode=Self}}" Value="True"/>
<Condition Binding="{Binding (Validation.Errors), RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource IsWarning}}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource ValMsg}}"/>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorControlTemplateRadiusWarning}"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
for usage, i can use as
<textbox style={staticresource ErrorStyleRadius} text={bind name, validationOnDataError=true}/>

Why don't you try this -
<ToolTip x:Key="MyToolTip"
DataContext={Binding PlacementTarget, RelativeSource={RelativeSource Self}}>
<Label Content="{Binding Text}"/>
</ToolTip>
<Style x:Key="ErrorStyleRadius" TargetType="{x:Type FrameworkElement}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding (Validation.HasError), RelativeSource={RelativeSource Mode=Self}}" Value="True"/>
<Condition Binding="{Binding (Validation.Errors), RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource IsError}}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="ToolTip" Value={StaticResource MyToolTip}>
</Setter>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorControlTemplateRadiusError}"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
You can give the property name in StaticResource. It will update the tooltip dynamically.

Also you can set the tooltip from your style if you want to set the text to Validation.Error like this -
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>

Related

DataTrigger inside a MultiDataTrigger?

I want to change 2 Properties on 2 different conditions using Multi-/DataTrigger.
I have 1 Button which changes its IsEnabled Property when ValidationRule returns an error.
I also want to change the Command Property of this Button but on other conditions.
<Button Content="Save">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource MaterialDesignFlatButton}">
<Setter Property="IsEnabled" Value="False" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=FirstNameBox}" Value="False" />
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=LastNameBox}" Value="False" />
[...]
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Now I want to implement another Trigger which changes the Binding of the Command Property when anoither Propertie's Binding equals to XY.
So i need to implement this next to the Datatrigger above.
<Setter Property="Command" Value="{Binding CreateEmployeeCommand}" />
<DataTrigger Binding="{Binding CurrentManageMode}" Value="2">
<Setter Property="Command" Value="{Binding EditEmployeeCommand}" />
</DataTrigger>
So is it even possible to have 2 Triggers at the same time?
Okay, i fixed it adding another Trigger just in Style.Triggers.
I didn't tried this cuz many Controls/Properties doesn't allow multiple Content.
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource MaterialDesignFlatButton}">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Command" Value="{Binding CreateEmployeeCommand}" />
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentManageMode}" Value="2">
<Setter Property="Command" Value="{Binding EditEmployeeCommand}" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=FirstNameBox}" Value="False" />
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=LastNameBox}" Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>

CheckBox text to change based on its IsChecked

I want a CheckBox text to changed based on the IsChecked status.
Tried with the following, but it complains about not having the property Content
<CheckBox Name="IsManualInput" IsChecked="{Binding Path=IsManual, Mode=TwoWay}" >
<CheckBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True" >
<Setter Property="Content" Value="Manual" />
<Setter Property="IsReadOnly" Value="True"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True" >
<Setter Property="Content" Value="Define manually..." />
<Setter Property="IsReadOnly" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
It's a simple mistake, you need to include TargetType in your Style.
e.g.
<Style TargetType="{x:Type CheckBox}">

MultiDataTrigger with AlternationIndex

I have a ListView declared as:
<ListView x:Name="Tree"
ItemsSource="{Binding ElementName=This, Path=Some.Path.Values}"
AlternationCount="2"
ScrollViewer.CanContentScroll="False">
and a style defined as
<UserControl.Resources>
<Style TargetType="ListViewItem">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="SteelBlue"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Gray"/>
</Style.Resources>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="White" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="GhostWhite" />
</Trigger>
</Style.Triggers>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<EventSetter Event="Loaded" Handler="ContinueLoading" />
</Style>
This combination produced the original desired behaviour, which is that of alternating background highlights. The new desired behaviour was to change that background color depending on the value of a property of a given ListView item; as such the Style.Triggers was changed to
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="White" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="GhostWhite" />
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="0"/>
<Condition Binding="{Binding Converter={x:Static controls:Converters.ObjectType}}" Value="{x:Type client:DocumentEntryTypeA}" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{Binding Converter={x:Static controls:Converters.LightColor}, UpdateSourceTrigger=PropertyChanged, Path=Status}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="1"/>
<Condition Binding="{Binding Converter={x:Static controls:Converters.ObjectType}}" Value="{x:Type client:DocumentEntryTypeA}" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{Binding Converter={x:Static controls:Converters.DarkColor}, UpdateSourceTrigger=PropertyChanged, Path=Status}" />
</MultiDataTrigger>
</Style.Triggers>
</UserControl.Resources>
The ObjectType Converter checks that an element is of a given class; the LightColor and DarkColor Converters produce the selected background values depending on the value of the Status property.
The issue with this code is that the binding I use seems to always produce an AlternationIndex value of '0', i.e. the Converter LightColor is used for every entry. In addition to the code above, I have also tried the following bindings with the same result:
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}, Path=AlternationIndex}" Value="0"/>
<Condition Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Path=(ItemsControl.AlternationIndex)}" Value="0"/>
Based on the examples I've seen most of the solutions don't separate the style from the object; in my case the style is defined separately within UserControl.Resources. However, since using a Trigger works fine, I'm not sure why a DataTrigger does not, or what would be required to get it working.
The first condition in your MultiDataTrigger finds the most recent ContentPresenter, and tries to bind to ContentPresenter.ItemsControl.AlternationIndex, and ItemsControl.AlternationIndex is not a valid property for ContentPresenter.
Try changing that to RelativeSource={RelativeSource Self} so you will be binding to the ItemsControl.AlternationIndex of the current object

XceedGrid. How to make cell editable related to other column(readonly)

I have boolean Property SpecValue what indicates that other property can be modified.
I can't find good solution how to do it.
I use next solution, but there is some bugs.
<xcdg:Column Title="Value" FieldName="Value" Width="100" MaxWidth="100" MinWidth="100">
<xcdg:Column.CellEditor>
<xcdg:CellEditor>
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<TextBox x:Name="txtSpecVal" Text="{xcdgg:CellEditorBinding}" IsReadOnly="False"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type xcdg:Row}},Path=DataContext.SpecificValue}" Value="False">
<Setter TargetName="txtSpecVal" Property="IsReadOnly" Value="True"/>
<Setter TargetName="txtSpecVal" Property="BorderBrush" Value="Transparent"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
</xcdg:Column.CellEditor>
This should work, This is an example of a style that targets DataCell and sets the "SpecificValue" cell's enabled property to false whenever it's own value is false. It should help you get started.
<Style.Triggers >
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource self},
Path=ParentColumn.FieldName}"
Value="SpecificValue"/>
<Condition Binding="{Binding
RelativeSource={RelativeSource self},
Path=ParentRow.DataContext.SpecificValue}"
Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Green" />
<Setter Property="IsEnabled" Value="False" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
You can also refer to the following blog post for a similar detailed example:
http://xceed.com/CS/blogs/techside/archive/2011/07/06/datacell-styling-vs-cellcontenttemplate.aspx

How to control visibility of text in all listboxitems on selection of one item in dynamic Listbox Menu?

I generate ListBox menu from XML. I use datatemplate to style the behavior of listboxitems on selection and other states. I need to hide all textblocks in all listboxitems on selection of the item which gets a value ‘retract’ from XML. Now, I am able to hide texblock only in listboxitem which has this value but cannot hide textblocks in other listboxitems. I am wondering if someone can help. Thank you in advance.
<DataTemplate x:Key="ListBoxItemDataTemplate">
<Grid x:Name="DataItem">
<Image x:Name="IconImage" Source="{Binding XPath=#icon}" Height="16" Margin="16,0,0,0" Stretch="None" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock x:Name="ListboxIemtextBlock" Text="{Binding XPath=#name}" />
<Image x:Name="ArrowImage" Height="10" Source="Resources/Images/arrow_collapsed_grey.png" Visibility="{Binding XPath=#state}"/>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True">
<Setter TargetName="ListboxIemtextBlock" Property="Foreground" Value="White"/>
<Setter TargetName="IconImage" Property="Source" Value="{Binding XPath=#iconSelected}"/>
<Setter TargetName="IconImage" Property="Height" Value="16"/>
<Setter TargetName="ArrowImage" Property="Source" Value="Resources/Images/arrow_collapsed_white.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True">
<Setter TargetName="ListboxIemtextBlock" Property="Foreground" Value="#FF6dacbe"/>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True" />
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter TargetName="ListboxIemtextBlock" Property="Foreground" Value="White"/>
</MultiDataTrigger>
<DataTrigger Binding="{Binding XPath=#retract}" Value="True" >
<Setter TargetName="ListboxIemtextBlock" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
It looks like I cannot control the visibility of all texblocks from a datatemplate. I think it should be done in the ListBox style. I was thinking to switch datatemplates with a second datatemplate that does not have texblock at all. I wanted to use multitrigger for conditions with values isSelected and XML-Binding to Binding="{XPath=#retract}. However, I cannot assign XPath binding for multitrigger in Listbox style. Perphaps, you might help to bind it correctly or have a better idea on how to hide texblocks.
<Style x:Key="ListBoxItemContainerStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate" Value="{StaticResource ListBoxItemDataTemplate}"/>
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter x:Name="contentPresenter"/>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Binding="{XPath=#retract}" Value="true"/>
</MultiTrigger.Conditions>
<Setter Property="ContentTemplate" Value="{StaticResource SelectedListBoxItemDataTemplate}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I populated XML with XMLDataProvider. I reference to xml this way:
<XmlDataProvider x:Key="PagesData" XPath="/Pages" Source="Data/DataSource.xml" />
XML:
<Pages xmlns="">
<page name="Item 1" icon="Resources/Iocn1.png" retract="False" />
<page name="Item 2" icon="Resources/Iocn2.png" retract="False" />
<page name="Item 3" icon="Resources/Iocn3.png" retract="True" /></Pages>
You can bind to the SelectedItem.retract for the Parent ListBox. This is a working example using Path instead of XPath (since I don't have your XML source) but you should be able to get it to work the same way
Add this trigger in the DataTemplate
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Path=SelectedItem.retract}" Value="True" >
<Setter TargetName="ListboxIemtextBlock" Property="Visibility" Value="Hidden"/>
</DataTrigger>

Resources