Is it possible to create a style for ToolTip that would place an image next to the Item on which the tool tip resides and then show the tool tip text when the user hovers over the image? Something like this:
Currently I am doing a StackPanel to add the image with the tool tip like so:
<StackPanel Orientation="Horizontal">
<CheckBox Content="Reload Employee Data"
IsChecked="{Binding AdjustmentSettings.ReloadEmployeeData}"
Grid.Row="0"
Grid.Column="0">
</CheckBox>
<Image Source="/DelphiaLibrary;Component/Resources/info.ico"
ToolTip="Check if you want to re-upload ...."/>
</StackPanel>
EDIT
Just to clarify, I am looking for a way to style ToolTip such that if I define ToolTip on any object (i.e., Button, CheckBox, etc.) the info image is shown and the tool tip text is placed on this info image.
I would like to be able to do something like this and still get the same as the stack panel above:
<CheckBox Content="Reload Employee Data"
IsChecked="{Binding AdjustmentSettings.ReloadEmployeeData}"
Grid.Row="0"
Grid.Column="0"
ToolTip="Blah blah blah..."
Style="{StaticResource ToolTipImageStyle}">
</CheckBox>
And be able to apply this ToolTipImageStyle to any control (i.e., Button, CheckBox, TextBox, etc.). If that isn't possible can I style an individual control and just create different styles for different controls (one for buttons, another for TextBlock, etc.)?
This should do it. I couldn't figure out the color so just change that.
Source 1
Source 2
<Image Source="/DelphiaLibrary;Component/Resources/info.ico" Width="25" Height="25">
<Image.ToolTip>
<ToolTip Background="LightBlue">
<TextBlock Width="200" TextWrapping="WrapWithOverflow">
Check if you want to re-upload table foxpro.hrpersnl from the source. <LineBreak />
Leave unchecked to use existing data that has been previously uplaoded.
</TextBlock>
</ToolTip>
</Image.ToolTip>
</Image>
Update 1:
Source 1
In the App.xaml add this:
<Application.Resources>
<Style TargetType="{x:Type ToolTip}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}" >
<TextBox Background="LightBlue" Width="200" TextWrapping="WrapWithOverflow" Text="{TemplateBinding ToolTip.Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Then in your XAML file change to:
Note: This will work with all object's tool tips.
<Image Source="Images/MenuImageZoomOut.png" Width="25" Height="25"
ToolTip="Check if you want to re-upload table foxpro.hrpersnl from the source. Leave unchecked to use existing data that has been previously uplaoded." />
The image:
If this doesn't work, try this: Source
Related
I'm working on styling a WPF ComboBox so that the ComboBoxItems have some additional data. The items look great when in the drop down, but once selected, the displayed item is not stretched/filling the ComboBox- it's all smushed to the left. I've done enough digging to figure out this is related to the MaterialDesign Theme being applied to the control. Without MeterialDesign being referenced in a demo project, the code works as anticipated.
<ComboBox Width="150"
Margin="2"
HorizontalContentAlignment="Stretch" <!-- No Effect //-->
materialDesign:HintAssist.Hint="Select Item"
ItemsSource="{StaticResource ExampleItems}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding DisplayText}" />
<Ellipse Grid.Column="1" Width="10" Height="10" Fill="{Binding Color}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
<!-- No Effect //-->
<!--<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource MaterialDesignComboBoxItemStyle}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ComboBox.ItemContainerStyle>-->
</ComboBox>
I've tried pretty much everything I can without luck- Including various controls inside the DataTemplate, stack panel, dock panel, etc....
I've created a minimum reproducible example here: ComboBoxDemo Project
I've included the ComboBox Style I pulled from Blend, to try to dig into what MaterialDesign is doing on top of the normal template. I see that there is an ItemContainerStyle for the selected item, but it looks like it's binding the HorizontialContentAlignment up the chain. Manually setting that to Stretch did not help.
So Hopefully a Xaml guru out there can pinpoint the issue...
I have a custom radio button based on togglebutton:
<Style TargetType="{x:Type local:ToolbarRadioButton}" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="Width" Value="60"/>
<Setter Property="Height" Value="60"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical">
<iconPacks:PackIconModern Kind="{Binding TbIcon, RelativeSource={RelativeSource AncestorType=RadioButton}}"
Height="30" Width="35" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding TbText, RelativeSource={RelativeSource AncestorType=RadioButton}}" FontSize="12"
HorizontalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I use this control to create four toggle/radio buttons. I've horizontal centered the items in datatemplate, but I end up with this:
Forecast and its icon seem to be centered, but the others are partially left-aligned. They all use the same control so shouldn't they all be centered?
EDITS FOR CLARITY:
It doesn't matter which order I put them in, Forecast is always the one that's aligned correctly.
There is no whitespace in the text nor is there whitespace in the images and all images are sized according to the control defined above. Here's the implementation portion in case it's useful, though they're all the exact same:
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="0">
<customs:ToolbarRadioButton TbText="Day" TbIcon="CalendarDay" GroupName="calViewType" x:Name="dayOnOff"/>
<customs:ToolbarRadioButton TbText="Week" TbIcon="CalendarWeek" GroupName="calViewType" x:Name="weekOnOff"/>
<customs:ToolbarRadioButton TbText="Month" TbIcon="CalendarMonth" GroupName="calViewType" x:Name="monthOnOff" IsChecked="True"/>
<customs:ToolbarRadioButton TbText="Forecast" TbIcon="PeopleMultiple" GroupName="calViewType" x:Name="forecastOnOff"/>
</StackPanel>
For future readers: I figured out the answer by digging into the documentation on Button. There is a property on buttons called HorizontalContentAlignment (and vertical, of course) that apparently needs to be set to align the visual content. You can't set the HorizontalAlignment property of the item that is the content explicitly; apparently, the button wants to do that for you.
so for example i have this xaml code
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid Width="50" Height="50" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button x:Name="PlayButton" Style="{DynamicResource MetroCircleButtonStyle}" Visibility="Visible"
Width="50" Height="50" HorizontalAlignment="Center"
VerticalAlignment="Center" Click="OnPlayButtonClicked"
d:DataContext="{d:DesignInstance local:MainWindow}">
<Rectangle Width="20"
Height="20">
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
<Rectangle.Fill>
<VisualBrush Stretch="Fill"
Visual="{StaticResource appbar_control_play}" />
</Rectangle.Fill>
</Rectangle>
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
</Button>
<Button x:Name="PauseButton" Style="{DynamicResource MetroCircleButtonStyle}" Visibility="Hidden"
Width="50" Height="50" HorizontalAlignment="Center"
VerticalAlignment="Center" Click="OnPauseButtonClicked"
d:DataContext="{d:DesignInstance local:MainWindow}">
<Rectangle Width="20"
Height="20">
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
<Rectangle.Fill>
<VisualBrush Stretch="Fill"
Visual="{StaticResource appbar_control_pause}" />
</Rectangle.Fill>
</Rectangle>
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
</Button>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
and inside my MainWindow.xaml.cs file i would like to edit the 'PlayButton' Visibility, but i can't seem to access it?
What is the correct way of accessing components like this?
Kind Regards - Corey.
The "PlayButton" resides inside a DataTemplate for the DataGridTemplateColumn.CellTemplate, which means that you will see one "PlayButton" for each row of the table.
So, the window can't have a "PlayButton" property to access the button, since there are many instances of it.
Usually if you have to control the Visibility of that button, you will have to do it by Binding.
In addition, since the DataGrid uses by default EnableColumnVirtualization and EnableRowVirtualization, a single instance of the button can be reused when you scroll the grid elements, so the button has to be able to match the cell content only by using the data present in that row.
For example if the grid displays 10 rows, when you scroll down by one row, the visual components used to show the first row, which goes out of sight, will be reused to show the eleventh row. So any change you could have made to the PlayButton of the first row, will remain in the eleventh one, unless you change it again.
Another advice I can give you is to not use a Grid, if you can, inside a celltemplate of a column because the Grid is quite heavy to render, and assuming that the grid could show at the same time dozens of rows, the redering could be very slow.
I think that in this case it could be better to use a CellTemplateSelector to show only a PlayButton or a PauseButton, each one on its own DataTemplate, basing on the content of the row, or to use a single button with a Style responding to DataTriggers that changes the appearance of the button itself.
You'd use a DataTrigger to toggle visibility :
<Button x:Name="PauseButton" ...>
<Button.Style>
<Style TargetType="{x:Type Button}">
<!-- Set Default Value here, not in Button Tag -->
<Setter Property="Visibility" Value="Collapsed" />
<!-- Use Trigger to update value based on a conditional statement -->
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
...
</Button>
Formentz's answer is correct that the actual Button object is hard to use because it is not individually created for each row. Instead, only the visible rows are created, and the .DataContext behind each row changes as you scroll through. If you want to toggle the Visibility of the button, it needs to be based off a databound property so it updates as users scroll through the rows.
How can replace default checkbox style with png image, for checked state and unchecked state.
Here is and what I try but is not complilated with xaml:
<CheckBox IsChecked="{Binding AirTemperatureGridChecked}">
<CheckBox.Background>
<Image Source="https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/checkbox_unchecked.png" Width="16" Height="16" />
</CheckBox.Background>
</CheckBox>
I try and this code but then image go in content is not replaced.
<CheckBox IsChecked="{Binding AirTemperatureGridChecked}">
<Image Source="https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/checkbox_unchecked.png" Width="16" Height="16" />
</CheckBox>
Is possible to replace default style?
In this particular case, you will need to fiddle with the Template of the CheckBox.
<CheckBox IsChecked="{Binding AirTemperatureGridChecked}">
<CheckBox.Template>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Image x:Name="Foo" Width="16" Height="16" Source="https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/checkbox_unchecked.png" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="Foo" Property="Opacity" Value="0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</CheckBox.Template>
I've made this one from scratch to just give an example of how quick and easy it is to get your own templates up and running for the design of controls.
As you can see, it's made of a grid, with your image inside, and below that is a trigger that will make the checkbox lower its opacity when unchecked.
You can put just about anything in that grid to design your checkbox as you would any window, and give it functionality with triggers.
Additionally (as giving each and every checkbox this mass of code would be unreasonable) you can give the controltemplate a key:
<ControlTemplate x:Key="WhateverYouWantToCallMe" TargetType="{x:Type CheckBox}">
<!-- Content ect... -->
</ControlTemplate>
Put it inside a Resource Dictionary and call it as a StaticResource for the checkbox instead, like so:
<CheckBox Template="{StaticResource WhateverYouWantToCallMe}"/>
I have a dialog in my WPF application which contains a ListBox. The ListBox uses the following DataTemplate to display its contents:
<DataTemplate x:Key="AlarmClassTemplate">
<CheckBox Content="{Binding Path=Value}"
IsChecked="{Binding IsChecked}" />
</DataTemplate>
I've also configured the following template and style to display when there is an error in the ListBox's contents:
<ControlTemplate x:Key="InputErrorTemplateA">
<DockPanel LastChildFill="True">
<Image DockPanel.Dock="Right"
Height="30"
Margin="5"
Source="{StaticResource ErrorImage}"
ToolTip="Contains invalid data"
VerticalAlignment="Center"
Width="30" />
<Border BorderBrush="Red"
BorderThickness="5"
Margin="5">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource InputErrorTemplateA}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<Binding Path="(Validation.Errors).CurrentItem.ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
And here's the XAML for the ListBox itself:
<ListBox FontSize="20"
FontWeight="Bold"
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="1"
Height="158"
ItemsSource="{Binding Path=IDs, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
ItemTemplate="{StaticResource AlarmClassTemplate}"
Margin="5,0,110,0"
Name="AlarmClassListBox"
ToolTip="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"
Visibility="{Binding Converter={StaticResource BoolToVisibility}, Path=DataTypeIsAlarms}" />
The validation logic for the data in the ListBox is that at least one item has to be checked off. If none of them are, the ListBox should display an error and the OK button on the dialog should be disabled.
The good news is that the OK button on the dialog is indeed disabled when nothing in the ListBox is checked. The bad news is that the Style doesn't seem to be working, in that no red border is displayed around the ListBox and the error image (a red circle with a white exclamation point inside) does not show.
I'm using the same exact ControlTempate and a similar Style on other controls on the same dialog and they work fine. What am I doing wrong? Is it the ListBox? Does ListBox validation work differently?
Indeed the problem is you weren't raising PropertyChanged event for your validation to gets fired.
But i can see one more issue in your code. You have set local value for tooltip on ListBox here:
ToolTip="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"
But you want different tooltip in case validation returns some error which you define in style triggers.
But, local value has higher precedence order than style triggers. So, your tooltip will never be set. So, you should move the tooltip to style setters to work:
<Setter Property="ToolTip"
Value="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"/>
MSDN link - Dependency property value precedence.
I found the answer to my problem in this post. It turns out that I have to raise the PropertyChanged event when the checkboxes change in order for the Validation logic to fire. Since the items in the ListBox implement INotifyPropertyChanged, it was easy to add an event listener for each item as it's added to the ListBox which raises the necessary event.
Thanks anyway.