I am designing my own tooltip in SilverLight 5 and need to pass several values to it when displaying it.
Here is the Style:
<Style x:Key="TooltipStyle" TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border BorderBrush="Blue" BorderThickness="2" Background="White">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Var Number: "></TextBlock>
<ContentPresenter x:Name="Content1"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1">
<TextBlock Text="Last Update Date: " />
<ContentPresenter x:Name="Content2"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am applying the style like so:
var customTooltip = new ToolTip
{
Style = (Style)Resources["TooltipStyle"],
Content = questions.Number[c]
};
ToolTipService.SetToolTip(textbox, customTooltip);
There is only one 'Content' property there, but I need to pass something to 'Content2' as well. (Please note the content is gathered as we do a 'for' loop.)
So the image that comes up, instead of having one variable, can have both the Var Number and the Last Update Date. Reputation too low to post image, here is the final look of the tooltip to give you an idea:
http://imgur.com/HYBbXMN
So that's the situation.
Now I am wondering if I can expose a second Content property? Or perhaps there is a smarter and better way to style the tooltip to meet my needs?
Please note this example requires two values (or 'Content') to be displayed but tooltip will expand to require more.
I will appreciate any ideas.
So to make it easier on ya, personally I just leverage things already available for that type of thing. Like for example using Tag to piggy back that sort of thing into the template.
An example (with some additions for setters and stuff you'll probably want to omit or change) like;
<Style x:Key="NiftyToolTipStyle" TargetType="ToolTip">
<Setter Property="FontFamily" Value="{StaticResource FontFamily}" />
<Setter Property="FontSize" Value="{StaticResource FontSize}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="White" />
<Setter Property="Padding" Value="3" />
<Setter Property="BorderThickness" Value="1,2" />
<Setter Property="BorderBrush" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border x:Name="Root"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="1"
Padding="{TemplateBinding Padding}"
Cursor="{TemplateBinding Cursor}">
<Border.Effect>
<DropShadowEffect Opacity="0.35" ShadowDepth="3" />
</Border.Effect>
<TextBlock>
<Run Text="{TemplateBinding Tag, StringFormat='Var Number: \{\0}'}"/>
<LineBreak/>
<Run Text="{TemplateBinding Content, StringFormat='Last Update Date: \{\0}'}"/>
</TextBlock>
<!--
<ContentPresenter Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}" />
-->
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This way you can just pass in one value to Content and another to Tag and you're good. You could also easily do other stuff, there's multiple options. Hope this helps, Cheers
Related
i've seen that is common to put a ControlTemplate inside a Style as in the following example
<Style x:Key="roundbutton" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
instead of just defininig the control template as a resurce
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
What are the advantages of defining the ControlTemplate inside a Style?
I make use of a resource dictionary with all my styles, icons and more.
Now I'd like to add my own titlebar implementing the title of the solution, my image and a ContentPresenter.
When using the WindowStyle I'd like to add application specific items inside this ContentPresenter, but I don't know how to proceed.
This is my WindowStyle. Inside the Grid you'll find the ContentPresenter I'd like to fill.
<Style TargetType="{x:Type Window}" x:Key="tkDarkWindowStyle">
<Setter Property="AllowsTransparency" Value="True"></Setter>
<Setter Property="Foreground" Value="{StaticResource tkBrandBlueBrush}"></Setter>
<Setter Property="Background" Value="{StaticResource exQuiteDarkBrush}"></Setter>
<Setter Property="WindowStyle" Value="None"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="BorderBrush" Value="{StaticResource exQuiteDarkBrush}"></Setter>
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="80" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<DockPanel LastChildFill="True">
<Border Background="{TemplateBinding Background}" DockPanel.Dock="Top"
Height="80" x:Name="titlebar">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0">
<Path DockPanel.Dock="Left" Margin="10" Stretch="Uniform" Fill="{TemplateBinding Foreground}" Data="{Binding Source={StaticResource tkPrimaryLogo}}" VerticalAlignment="Center">
</Path>
<Label Content="{TemplateBinding Title}" Foreground="{TemplateBinding Foreground}" Margin="10" DockPanel.Dock="Left" FontSize="26" VerticalAlignment="Center"/>
</DockPanel>
<ContentPresenter Grid.Column="1"/>
</Grid>
</Border>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1" Padding="4">
<ContentPresenter/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I used the style like this and tried to edit the template and add for example some buttons to the titlebar.
<Window.Resources>
<Style TargetType="{x:Type Window}" x:Key="newWindow" BasedOn="{StaticResource tkDarkWindowStyle}">
<!--here add application specific items? -->
</Style>
</Window.Resources>
How can I use the WindowStyle in my application and add specific items to the space i left at the titlebar?
Since the Window only has a single Content property, it makes no sense to include more than one <ContentPresenter /> element in the ControlTemplate.
You may want to create a custom class that inherits from Window and adds a dependency property called "TitleBarContent" or something. You can then add a ContentControl to the template that binds to this property:
<ContentControl Content="{TemplateBinding TitleBarContent}" />
You can set the value of the dependency property in a style setter as usual:
<Style TargetType="{x:Type local:YourWindowClass}" x:Key="newWindow" BasedOn="{StaticResource tkDarkWindowStyle}">
<Setter Property="TitleBarContent">
<Setter.Value>
<TextBlock>title...</TextBlock>
</Setter.Value>
</Setter>
</Style>
I am making a numeric text box, which can also contain various additional symbols to denote if the data contained in the control is a percentile, radius, etc. For this I have a grid with a text box to the left and a TextBlock to the right. Here is a picture:
The problem that I am having with this, however, is that if the mouse is over the textblock, and I click, I cannot get the TextBox to gain focus. I have tried _textbox.Focus() on mouse down of the textblock, as well as on the parent grid. This did not work.
After some googling, I read that I could put FocusManager.FocusedElement="{Binding ElementName=_textbox}" on the parent Grid, and this would solve my problem. However, even with this, the Textbox still does not gain focus. I've even tried making neither the textbox or textblock hit-testable, and instead use the grid itself as a hit test, but even with this, the textbox itself still will not gain focus. I'm at a loss of what to do here. Does anyone know how I can make the textbox gain focus, when either the parent grid is clicked, or the textblock is clicked? Or Both?
Here is my XAML:
<UserControl
x:Class="VoidwalkerEngine.Editor.Controls.NumericTextBox"
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"
Height="32"
d:DesignWidth="80"
BorderThickness="0"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="ButtonTop" TargetType="Button">
<Setter Property="Background" Value="White" />
<Setter Property="TextBlock.TextAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
x:Name="ButtonBackground"
Background="{DynamicResource Voidwalker_Gradient_Button}"
BorderBrush="{DynamicResource Voidwalker_Brush_Border}"
BorderThickness="1,0,0,1"
CornerRadius="0,2,0,0">
<ContentPresenter
x:Name="contentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource Voidwalker_Gradient_ButtonPressed}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource VoidwalkerButtonBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ButtonBottom" TargetType="Button">
<Setter Property="Background" Value="White" />
<Setter Property="TextBlock.TextAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
x:Name="ButtonBackground"
Background="{DynamicResource Voidwalker_Gradient_Button}"
BorderBrush="{DynamicResource Voidwalker_Brush_Border}"
BorderThickness="1,1,0,0"
CornerRadius="0,0,2,0">
<ContentPresenter
x:Name="contentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource Voidwalker_Gradient_ButtonPressed}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="ButtonBackground" Property="Background" Value="{DynamicResource VoidwalkerButtonBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Border
Background="{DynamicResource Voidwalker_Brush_ContextArea}"
BorderBrush="{DynamicResource Voidwalker_Brush_Border}"
BorderThickness="1"
CornerRadius="3">
<Grid Focusable="False">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="23" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Border
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
BorderThickness="0"
CornerRadius="2,0,0,2">
<Grid
Cursor="IBeam"
FocusManager.FocusedElement="{Binding ElementName=_textbox}"
MouseDown="_backAreaGrid_OnClick">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<TextBox
x:Name="_textbox"
Grid.Column="0"
Margin="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Background="{DynamicResource VoidwalkerContextBrush}"
BorderThickness="0"
CommandManager.PreviewExecuted="_numericDisplayTextBox_OnPreviewExecuted"
Foreground="{DynamicResource Voidwalker_Brush_ActiveTextForeground}"
GotFocus="_textbox_OnGotFocus"
LostFocus="_numericDisplayTextBox_OnLostFocus"
MouseDoubleClick="_textbox_OnMouseDoubleClick"
PreviewKeyDown="_numericDisplayTextBox_OnPreviewKeyDown"
PreviewMouseWheel="_numericDisplayTextBox_OnPreviewMouseWheel"
Text="0"
TextAlignment="Right"
TextChanged="_numericDisplayTextBox_OnTextChanged" />
<TextBlock
x:Name="OperatorDisplayTextBox"
Grid.Column="1"
VerticalAlignment="Center"
Cursor="IBeam"
Foreground="{DynamicResource Voidwalker_Brush_ActiveTextForeground}"
Text="%" />
</Grid>
</Border>
<Button
Grid.Row="0"
Grid.Column="1"
BorderThickness="1,0,0,0"
Click="Increment_Button_OnClick"
Style="{DynamicResource ButtonTop}">
<Path Data="M 1,4.5 L 4.5,1 L 8,4.5" Fill="{DynamicResource Voidwalker_Brush_ActiveTextForeground}" />
</Button>
<Button
Grid.Row="1"
Grid.Column="1"
BorderThickness="1,0,0,0"
Click="Decrement_Button_OnClick"
Style="{DynamicResource ButtonBottom}">
<Path
ClipToBounds="True"
Data="M 1,1.5 L 4.5,5 L 8,1.5"
Fill="{DynamicResource Voidwalker_Brush_ActiveTextForeground}" />
</Button>
</Grid>
</Border>
</UserControl>
I figured it out after reading this page. I don't know why this code works...like, at all actually. It seems like i'm using a backwards, roundabout way into the control to avoid threading issues... isn't that what the Dispatcher is for? So is it safe to assume that a .Focus() method does nothing unless it's used like below? It's whatever, I guess, less hair pulling now, and more coding. Here is the code that worked for me. All I had to do was add this to the parent grid's MouseDown event:
private void _backAreaGrid_OnMouseDown(object sender, MouseButtonEventArgs e)
{
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate
{
_textbox.Focus();
}));
}
The textbox gains focus regardless of what I click on in the surrounding grid.
I have crowded Page in my project and I want to place too many Checkbox control in a single page, so I'm looking for a way to resize my checkboxes.
When I change height and width of my checkbox, some part of its text disappear, In other word I need to scale my checkbox and make some tiny checkbox.
You can of course scale it down by using ScaleTransform but modifying its style gives you more flexibility.
Here's an example -
<Style x:Key="TinyCheckBoxStyle"
TargetType="CheckBox">
<Setter Property="Padding"
Value="4,0,0,0" />
<Setter Property="HorizontalContentAlignment"
Value="Left" />
<Setter Property="FontSize"
Value="11" />
<Setter Property="MinWidth"
Value="0" />
<Setter Property="MinHeight"
Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Grid x:Name="RootGrid"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<!-- Add default visual states back in here -->
</VisualStateManager.VisualStateGroups>
<Grid>
<Rectangle x:Name="NormalRectangle"
Fill="{ThemeResource CheckBoxCheckBackgroundFillUnchecked}"
Height="12"
Stroke="{ThemeResource CheckBoxCheckBackgroundStrokeUnchecked}"
StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}"
UseLayoutRounding="False"
Width="12" />
<FontIcon x:Name="CheckGlyph"
Foreground="{ThemeResource CheckBoxCheckGlyphForegroundUnchecked}"
FontSize="{TemplateBinding FontSize}"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Glyph=""
Opacity="0" />
</Grid>
<ContentPresenter x:Name="ContentPresenter"
AutomationProperties.AccessibilityView="Raw"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Content="{TemplateBinding Content}"
Grid.Column="1"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
TextWrapping="Wrap"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Basically, you need to reduce the size of NormalRectangle, CheckGlyph and the FontSize. Note I have removed the visual states to simplify the answer, you just need to add them back from the default style.
I am working on a WPF 4.0 window with many status indicators using Labels. In one example, the Labels turn GREEN and read "Available" if the bound property's enumeration Foo is AVAILABLE. The labels turn RED and read "Not Available" if the bound property is NOTAVAILABLE. I also have other labels that indicate status of different bound enum Bar, and they turn different colors and have different content based on this value.
I am able to successfully bind and turn one label's color and text based on the value of a bound property. I use a rather lengthy ControlTemplate in a DataTrigger's Setter just to change the label's text.
Here's what I have so far:
<Window> ...
xmlns:cst="clr-namespace:CstCommonTypes;assembly=CstCommonTypes"
...
</Window>
<Label x:Name="Avail_Out_LBL" HorizontalAlignment="Left" Margin="111,44,0,0" VerticalAlignment="Top" Width="124" Height="18" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" SnapsToDevicePixels="False" Grid.Column="1" Padding="0">
<Label.Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Background" Value="#FFC08100"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="24"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Degraded"
Grid.Column="1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding MonitorAndControlData.Availability}" Value="{x:Static cst:Foo.Available}">
<Setter Property="Background" Value="#FF567E4A"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="24"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Available"
Grid.Column="1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding MonitorAndControlData.Availability}" Value="{x:Static cst:Foo.NotAvailable}">
<Setter Property="Background" Value="LightCoral"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="22"/>
</Grid.ColumnDefinitions>
<TextBlock Text=" Not Available"
Grid.Column="1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
The above works, but I was wondering if I can reuse either the Style and give it different DataTrigger bindings or just reuse the ControlTemplate to cut down on xaml code. I tried to see if I could define a resource, but I couldn't figure out how to give it different Template Bindings for all the Labels.
Any help would be greatly appreciated.
If you need more properties to bind to, then turn it into a custom control (i.e. a class that inherits from Control), then you can add additional dependency properties on said control, which you can then bind to in the template.
It won't be possible to reuse the style if the bindings are not the same.
What you could do is make yourself a user control for your status indicators labels, Inside which you will create a Dependency Property (lets name it Availability) on which you will bind your Triggers to. But, you will have to make sure that you will always need the same type for your triggers. If the Availability binding is not of the same type for each of your labels, this solution won't work.
Here is a link on how to use Dependency Properties :
http://www.wpftutorial.net/dependencyproperties.html