Material Design and IntegerUpDown Tooltip to Display Error - c#

I'm using MaterialDesign and the Xceed IntegerUpDown control in a WPF project. I'm trying to display errors associated with the updown control as a tooltip when the mouse hovers over the control.
I've gotten this to work with TextBoxes and TextBlocks by using the following global style:
<Style TargetType="{x:Type TextBox}"
BasedOn="{StaticResource CustomizedMaterialDesignTextBox}" >
<Setter Property="Margin" Value="5"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}"
Background="{DynamicResource ValidationErrorBrush}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}"
DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
But when I tried to adapt this to the updown control as follows, no tooltip is displayed:
<Style TargetType="{x:Type xctk:IntegerUpDown}">
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}"
Background="{DynamicResource ValidationErrorBrush}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}"
DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
No error message about a failed binding or whatnot is displayed in the output window when the app is run in the VS 2017 debugger and an error condition is triggered.
Interestingly, a red border appears around the control when an error condition exists, even without the custom updown style.

You didn't show how exactly you're binding it but remember to 1) specify UpdateSourceTrigger and 2) actually hover over it ! Here's a MCVE showing that it actually works with no problem.
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:xctk="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
xmlns:local="clr-namespace:WpfApp5"
x:Class="WpfApp5.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type xctk:IntegerUpDown}">
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}"
Background="{DynamicResource ValidationErrorBrush}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}"
DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Window.DataContext>
<local:SampleViewModel/>
</Window.DataContext>
<Grid>
<xctk:IntegerUpDown Text="{Binding MyInteger, UpdateSourceTrigger=PropertyChanged}"
FontSize="24"
Width="125"
Height="50"/>
</Grid>

Related

Bind to controls property in corresponding style

I want to define a style for the text box and within the style I want to bind to a property which the corresponding style applies to. Something like this:
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Text="{Binding ????Bind to the textbox TEXT property????}">
</TextBlock>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Is this possible at all?
Here the full Window:
<Window x:Class="StyleBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StyleBinding"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Text="{Binding Text, RelativeSource={RelativeSource Self}}"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBox HorizontalAlignment="Left" Height="34" Margin="235,140,0,0" TextWrapping="Wrap" IsEnabled="True"
Text="Just a simple text" VerticalAlignment="Top" Width="284">
</TextBox>
</Grid>
</Window>
You just have to use a RelativeSource binding to access the Text property of the TextBox.
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Self}}"/>
In case you build a custom tool tip template in your style, you can do it like this.
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<TextBlock Text="{Binding PlacementTarget.Text, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}"/>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
The PlacementTarget of the ToolTip is the TextBox here.
Here's a working example:
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
</Style>
The key is to use a RelativeSource binding of Self.
There's no need to set a trigger on IsEnabled because a ToolTip will only display on an enabled control by default.

Do you have a solution which makes Foreground works like Background?

Please run following code and put mouse cursor on TextBlock in order to see what following code is doing.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock Foreground="Blue" Text="www.google.com" Height="20" Width="100">
<TextBlock.Style>
<Style>
<Style.Triggers>
<Trigger Property="TextBlock.IsMouseOver" Value="True">
<Setter Property="TextBlock.Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Window>
Then replace above code from
<Setter Property="TextBlock.Background" Value="Red"/>
to
<Setter Property="TextBlock.Foreground" Value="Red"/>
and see that Foreground is not working.
Do you have a solution which makes Foreground works like Background?
The reason it is not working is that you set Foreground="Blue" explicitly on your TextBlock. This will override any value from style triggers. Change your XAML like this:
<TextBlock Text="www.google.com" Height="20" Width="100">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

How To Style ListBoxItem

<Border Grid.Row="1" Padding="15" Margin="15" BorderBrush="LightBlue" Background="AliceBlue" BorderThickness="1">
<ListBox ItemsSource="{Binding Configs}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="False" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<view:Config />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
This is the code I've written in XAML. However, it doesn't appear to affect anything.
There are so many posts on SO with similar questions but all of their response are "use ListBox.ItemContainerStyle" which I've done :S Such as There is no ListBox.SelectionMode="None", is there another way to disable selection in a listbox? and WPF, XAML: How to style a ListBoxItem using binding on property of ListBox ItemsSource object?
What I would expect is that there is no background, no border and the item is not focusable.
What have I done wrong?
Redefine the ControlTemplate of your ListBoxItem. The sample code below uses a redish color just to make the point, but you can just replace it with Transparent:
<Window x:Class="WpfApplication235.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication235"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:Array x:Key="SampleData" Type="{x:Type sys:String}">
<sys:String>Item 1</sys:String>
<sys:String>Item 2</sys:String>
<sys:String>Item 3</sys:String>
<sys:String>Item 4</sys:String>
<sys:String>Item 5</sys:String>
</x:Array>
<Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<TextBlock Text="{Binding}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#1FFF0000"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox x:Name="listBox" ItemsSource="{StaticResource SampleData}"
ItemContainerStyle="{StaticResource ListBoxItemStyle1}"
Height="150" Margin="0" Width="250"/>
</Grid>
and using a Transparent background, no focus, no highlighting, as required:
You can use style in resource like:
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#D8D8D8"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="FontWeight" Value="400"/>
<Setter Property="Height" Value="30"/>
<!--and so on whatever you want...-->
</Style>
</Window.Resources>
And remove code like:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="False" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
And don't use any property in listBox which is used in style, other wise it will not behave which is described in style.

WPF Listbox with separators, missing highlighted colors

I have a listbox (C# WPF) which gets filled on startup. I would like a separator between every item in the list and I have found this code from another old post and it's actually working, but when I use the code, I loose the highlighted and selected colors instead and I can't figure out where it's going wrong.
How can I get back those highlighted and selected colors?
Here is the code I'm using.
<ListBox x:Name="radioBox" HorizontalAlignment="Left" Height="494" Margin="14,14,0,0" VerticalAlignment="Top" Width="287" Background="{x:Null}" FontFamily="Calibri" FontWeight="Thin" FontSize="25" Foreground="#FFEDEDF7" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" BorderThickness="1" Padding="30,30,0,0" >
<ListBox.ItemBindingGroup>
<BindingGroup/>
</ListBox.ItemBindingGroup>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel>
<Separator x:Name="Separator" Background="White" Opacity="0.1" Height="20"/>
<ContentPresenter/>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Separator" Value="Collapsed"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Try below code. It's a sample done by me and it should work.
<Window x:Class="ListBoxStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:ListBoxStyle"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="_ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="_Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_Border" Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox ItemContainerStyle="{DynamicResource _ListBoxItemStyle}"
Width="200" Height="250"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBoxItem>Hello</ListBoxItem>
<ListBoxItem>Hi</ListBoxItem>
</ListBox>
</Grid>

Changing WPF Listbox SelectedItem text color and highlight/background Color using C#

I am trying to change the highlighted(selected) color and the highlighted text color of a wpf listbox at runtime. I have tried creating a style and applying it as follows:
Style s = new Style(typeof(ListBox));
s.Resources.Add(SystemColors.HighlightBrushKey, Setting.ListSelectedColor);
s.Resources.Add(SystemColors.HighlightTextBrushKey, Setting.ListSelectedTextColor);
lstGames.Style = s;
But this seems to do nothing. Is there any way to achieve this?
EDIT:
Per suggestions, I tried using DynamicResources to achieve this, but so far this has not been successful either. My code for this:
DYNAMICRESOURCES
<UserControl.Resources>
<Color x:Key="ListTextSelectedColor"/>
<Color x:Key="ListSelectedColor"/>
</UserControl.Resources>
LISTBOX
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden"
Name="lstGames" Margin="20" Grid.Row="2" Grid.Column="2"
SelectionChanged="lstGames_SelectionChanged" Grid.RowSpan="2" Grid.ColumnSpan="2"
Background="{x:Null}" BorderBrush="{x:Null}" SelectionMode="Single"
FontSize="18" FontFamily="OCR A Extended">
<Style TargetType="ListBox">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="{DynamicResource ListSelectedColor}"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{DynamicResource ListSelectedColor}"/>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="{DynamicResource ListTextSelectedColor}"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="{DynamicResource ListTextSelectedColor}"/>
</Style.Resources>
</Style>
</ListBox>
APPLYING RESOURCES IN C#
this.Resources["ListSelectedColor"] = SETING.ListSelectedColor.Color;
this.Resources["ListTextSelectedColor"] = SETTING.ListSelectedTextColor.Color;
Solution:
<Window x:Class="ListBoxStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:ListBoxStyle"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="_ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="_Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_Border" Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox ItemContainerStyle="{DynamicResource _ListBoxItemStyle}"
Width="200" Height="250"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBoxItem>Hello</ListBoxItem>
<ListBoxItem>Hi</ListBoxItem>
</ListBox>
</Grid>
</Window>
Thanks to Vinkal and failedprogramming, I got everything working beautifully. I created the following Resources:
<UserControl.Resources>
<SolidColorBrush x:Key="ListTextSelectedColor" x:Shared="False"/>
<SolidColorBrush x:Key="ListSelectedColor" x:Shared="False"/>
<Style x:Key="_ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="_Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_Border" Property="Background" Value="{DynamicResource ResourceKey=ListSelectedColor}"/>
<Setter Property="Foreground" Value="{DynamicResource ResourceKey=ListTextSelectedColor}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
And then applied the style to my listbox with:
ItemContainerStyle="{DynamicResource ResourceKey=_ListBoxItemStyle}"
And finally, change the solidcolorbrush resources (therefore changing the setter values) in my C# code by doing the following:
this.Resources["ListSelectedColor"] = EmulatorPage.ListSelectedColor;
this.Resources["ListTextSelectedColor"] = EmulatorPage.ListSelectedTextColor;
Thank you to both of you!
To all the neigh-sayers out there... do not lose hope! it can be done!
I started off with VSS right-click on the listbox and used every "Edit Template" and "Edit Additional Templates" for each thing available until I found the how these things work.
You start off quite simply with a list box, bound to MVVM as normal.
<ListBox Width="100"
x:Name="myComboBox" Margin="8"
ItemsSource="{Binding ListBoxListSource}"
SelectedIndex="{Binding ListBox}">
</ListBox>
In UserControl or Window Resources set up a few things....
ListBoxStyle - This styles the main container of the listbox, you can set the borders, margins, padding etc of the main box here. For my example I'm just getting rid of everything to de-style it.
<UserControl.Resources>
<Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
</UserControl.Resources>
ItemContainerStyle - This is the bit that people say can't be re-styled - it contains the "windows-selector-blue" bar when an item is selected, but fear not this too can be re-styled (merge this UserControl.Resources section in combination with the above one).
This section is> changing the template of the ItemContainer from whatever it is to a Border, setting a top margin of 3 to pad things out and setting up a style. All we're doing with this style is adding 3px transparent border to the left and right of the item. Then in the Triggers>IsSelected (target of myBorder), changing the border Brush to Red.
<UserControl.Resources>
<Style x:Key="ItemContainerStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="myBorder"
Padding="0" Margin="0 3 0 0"
SnapsToDevicePixels="true"
Style="{DynamicResource borderContent}">
<ContentPresenter />
</Border>
<ControlTemplate.Resources>
<Style x:Key="borderContent" TargetType="Border">
<Setter Property="BorderThickness" Value="3 0 3 0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
</Style>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="myBorder" Property="BorderBrush" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
ListBoxItemDataTemplate - The next step is to make the item container that displays your data. In my example the YourTextBlockStyler has a trigger on the Text>binding and changes the foreground and background colours of the text. Take note that the foreground and background of the Listbox style are set to transparent, so you have to over ride them in your TextBlock style if you want to see anything.
<UserControl.Resources>
<DataTemplate x:Key="ListBoxItemDataTemplate">
<TextBlock Text="{Binding}" Style="{StaticResource YourTextBlockStyler}"/>
</DataTemplate>
</UserControl.Resources>
Back to the listbox - Now we've set up all the styles and templates in the Resources section we can update the listbox with Style="" ItemContainerStyle="" and ItemTemplate=""
<ListBox Width="100"
x:Name="myComboBox" Margin="8"
ItemsSource="{Binding ListBoxListSource}"
SelectedIndex="{Binding ListBox}"
Style="{StaticResource ListBoxStyle}"
ItemContainerStyle="{StaticResource ItemContainerStyle}"
ItemTemplate="{StaticResource ListBoxItemDataTemplate}">
</ListBox>
Then your boring list box will transform magically in to a totally restyled list box with red border selector
From into
All without editing a single System.ResourceBrush =]

Categories