I can not clean the text property of a TextBox when the user clicks inside it. The TextBox is inside a HierarchicalDataTemplate but the trigger doesn't work.
My code is as follows:
<HierarchicalDataTemplate x:Key="FoldersTemplate"
DataType="{x:Type vm:FolderViewModel}"
ItemsSource="{Binding Children}">
<Border>
<Grid>
<TextBox>
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Text" Value="{Binding Name}" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Text" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</Border>
</HierarchicalDataTemplate>
The action I would like to happen is that when the user clicks on the text, it disappears. How can I solve this?
Thanks a lot.
Related
I have created view models for the tree view. Also created their bindings. I created style trigger so that whenever a tree view item is selected, its background is changed. But the background does not change.I handled the item selected and left mouse down events of tree view item to see if the item is selected or not. But both the events do not fire. Below is the XAML.
<TreeView Grid.Row="0" x:Name="TreeViewLocalSystem" BorderBrush="Transparent" Panel.ZIndex="0">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundColor}"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="Transparent"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}" DataType="{x:Type local:LocalTreeViewItemModel}">
<TreeViewItem Header="{Binding Path=Text}" Selected="TreeViewItem_Selected" HorizontalAlignment="Left" FontSize="{StaticResource MediumFontSize}" MouseLeftButtonDown="TreeViewItem_MouseLeftButtonDown" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
What is it that I am doing wrong?
Edit: Another thing that I noticed is that MouseDown event is fired when I do right click but does not fire on left mouse button click.
You could handle the PreviewMouseLeftButtonDown event for the TreeViewItem:
<TreeView Grid.Row="0" x:Name="TreeViewLocalSystem" BorderBrush="Transparent" Panel.ZIndex="0">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="TreeViewLocalSystem_PreviewMouseLeftButtonDown" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundColor}"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="Transparent"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}" DataType="{x:Type local:LocalTreeViewItemModel}">
<TextBlock Text="{Binding Path=Text}" HorizontalAlignment="Left" FontSize="{StaticResource MediumFontSize}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
private void TreeViewLocalSystem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//...
}
I have a readonly TextBox control with a static resource, looks like this:
<Style TargetType="TextBox" x:Key="MyEditTextEditor">
<Setter Property="FontFamily" Value="{Binding Path=TextEditorFontFamily, ElementName=LogViewerProperty}" />
<Setter Property="FontWeight" Value="{Binding Path=TextEditorFontWeight, ElementName=LogViewerProperty}" />
<Setter Property="FontSize" Value="{Binding Path=TextEditorFontSize, ElementName=LogViewerProperty}" />
<Setter Property="FontStyle" Value="{Binding Path=TextEditorFontStyle, ElementName=LogViewerProperty}" />
<Setter Property="TextWrapping" Value="{Binding Path=WordWrapping, ElementName=LogViewerProperty, Converter={StaticResource BoolToTextWrap}}" />
<Setter Property="Text" Value="{Binding Message, Mode=OneWay}" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBox Text="{TemplateBinding Text}" BorderThickness="0" Margin="-3,-1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Opacity="0.4" Color="{Binding Source={x:Reference LogViewerProperty}, Path=TextEditorSelectionColor}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
It's embedded into a ListBox. All works fine, but when I want to get the selected text, the property is always string.Empty. The SelectionChanged event works perfect. Any suggestions? At the moment I do not know, why the SelectedText is string.Empty.
Here is the SelectionChanged event
private void ReadOnlyEditor_SelectionChanged(object sender, RoutedEventArgs e)
{
LOG.Debug("Current text {3}; selection {0} length {1}, start {2}", readOnlyEditor.SelectedText, readOnlyEditor.SelectionLength, readOnlyEditor.SelectionStart, readOnlyEditor.Text);
}
And yes, the text is selected in the control, but the property is empty. In readOnlyEditor.Text exists the right text.
Put your data binding into the ListBoxItem, then call the data from the ListBoxItem. Then the whole ListBoxItem is selectable. e.g.
<ListBox SelectionChanged="ListItemSelected" ItemTemplate="{StaticResource SelectedTextTemplate}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
.../...
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Build your data template or control template outside of the ListBox e.g.
<DataTemplate x:Key="SelectedTextTemplate">
<TextBox Text="{Binding SelectedText}"/>
</DataTemplate>
I would like to set Triggers for the controls in a DataTemplate. Whenever I set a property of the control within the DataTemplate, it seems not working. However, If do not set the property within the TextBlock inside the DataTemplate, then I can see the effect of Trigger in the style (it works). I am not sure whether using Style Triggers with DataTemplate is good or not! The XAML is below;
<Grid>
<Grid.Resources>
<Style TargetType="TextBlock" x:Key="BlockOf">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="ExtraBold" />
<Setter Property="FontSize" Value="22" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
...........
DataTemplate for the button,
<Button.ContentTemplate>
<DataTemplate DataType="Button">
<TextBlock Style="{DynamicResource BlockOf}" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"
FontStyle="Italic" FontSize="9"/>
</DataTemplate>
</Button.ContentTemplate>
I can see two problems here. First one is that current trigger will work only for TextBlock inside Button, not over whole Button. You can change that by using DataTrigger with RelativeSource binding. Second problem is that even when mouse is over TextBlock Style.Trigger cannot overwrite local value that you set against TextBlock so you need to bring default values as Setter into your Style. Check Dependency Property Setting Precedence List
<Style TargetType="TextBlock" x:Key="BlockOf">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="FontSize" Value="9"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=IsMouseOver}" Value="True">
<Setter Property="FontWeight" Value="ExtraBold" />
<Setter Property="FontSize" Value="22" />
</DataTrigger>
</Style.Triggers>
</Style>
and then TextBlock simply
<TextBlock Style="{DynamicResource BlockOf}" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" />
I have a templated treeview that is working just as i want, but i have a context menu which allows for a tier 1 node to be marked as "default".
I have a datatrigger which reacts to a property in the viewmodel, which should change the fontweight to bold just to visually show that this is the default node. But the setter will not change the fontweight on the button no matter what!
However if i change another value, like the foreground color for example, it works just fine, font size also no problem.
Why is this, can anyone explain this? Here is some code if needed:
Trigger:
<HierarchicalDataTemplate ItemsSource="{Binding Children,Mode=TwoWay,NotifyOnSourceUpdated=True}">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Image x:Name="nodeImg" Source="{Binding Image}" MaxHeight="16" MaxWidth="16"/>
<Button x:Name="nodeButton" Content="{Binding Name}" Command="{Binding Command}" Style="{StaticResource TreeMenuButton}"/>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem},Path=IsExpanded}" Value="True">
<Setter TargetName="nodeImg" Property="Source" Value="{Binding ImageExpanded}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding IsDefaultConnection}" Value="True">
<Setter TargetName="nodeButton" Property="FontWeight" Value="Bold"></Setter>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
Default style on button:
<Style x:Key="TreeMenuButton" TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="MinHeight" Value="23" />
<Setter Property="MinWidth" Value="75" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border"
CornerRadius="0"
BorderThickness="0"
Background="Transparent"
BorderBrush="Transparent">
<ContentPresenter Margin="2"
HorizontalAlignment="Left"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'd be surprised if your code even built as you can't add a DataTrigger into a UIElement.Triggers collection. Try using a Style instead (this definitely works):
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsDefault}" Value="True">
<Setter Property="TextBlock.FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
If by some miracle your DataTemplate does work in a UIElement.Triggers collection, then try using the class name as well as the property name:
<Setter Property="TextBlock.FontWeight" Value="Bold" />
I have an ItemsControl (let's say a ListBox) and I have a DataTemplate for the contents. When I press a button, I want all ListBoxItems to be validated. This works.
Yet, although all items are properly validated and I can retrieve error messages for them, WPF does only show the ValidationError.Template for the SelectedItem of the ListBox in question. It does not display the ValidationError.Template for the other items which failed validation. I do update the source of the binding for every item and the Validation.HasError Property is set to true for them! Just the visuals are missing, the style is not being applied!
Has anyone got a solution for the problem?
Sample
A TextBox Style:
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<AdornedElementPlaceholder Name="MyAdorner" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="{DynamicResource TextBoxBackgroundBrush}" />
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{DynamicResource TextBoxFocusBackgroundBrush}" />
</Trigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Background" Value="{DynamicResource ErrorBrush}" />
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
A DataTemplate for a Person Entity:
<DataTemplate DataType="{x:Type entities:Person}" x:Key="PersonItemStyle">
<Grid>
<TextBox x:Name="SomeTextBox">
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validators:RequiredFieldValidationRule ErrorMessage="Please enter a name!" />
</Binding.ValidationRules/>
</Binding>
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
Somewhere in some control:
<ListBox Grid.Row="1" x:Name="ListBoxPersons" Style="{DynamicResource ListBoxStyle}" ItemsSource="{Binding Path=Persons}"
ItemContainerStyle="{StaticResource PersonItemStyle}">
</ListBox>
Then try editing a few persons, for example set their names to null or use any erroneous binding. When you validate, the triggers for Validation.HasError will only be set for the selected item.
How can one work around that problem?
You are setting the ItemContainerStyle to a DataTemplate, why? The style is applied to all textboxes so you shouldn't have to set the ItemContainerStyle separately.