How to make diamond-shaped button style with text that is displayed horizontally like this
I did this, but don't know what to do next:
<Style x:Key="Button">
<Setter Property="Button.Height" Value="40"/>
<Setter Property="Button.Width" Value="40"/>
<Setter Property="Button.RenderTransform">
<Setter.Value>
<RotateTransform Angle="45"/>
</Setter.Value>
</Setter>
</Style>
The easiest option is to not define your text content utilizing the Button control Content dependency property, but instead define your Text in a separate control such as the obvious TextBlock, since the content is also going to be rotated 45 degrees due to the render transform.
In your style, if you want your button to look exactly as the one in the link that you provided, you should also set the following dependency properties: BorderThickness, BorderBrush (Black) and Background (White).
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Height" Value="100"/>
<Setter Property="Width" Value="100"/>
<Setter Property="BorderThickness" Value="4"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Background" Value="White"/>
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="45"/>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
Place the pair Button/TextBlock inside the same layout area, and overlap the Button control with the TextBlock. Depending on the dimensions to which you set your Button control element, you can easily play with the Margin dependency property on the TextBlock control and put it exactly on your desired place.
This would be my option if I were to choose a Grid as the layout container for these 2 control definitions.
If instead I choose to use a Canvas, I would utilize the attached properties Canvas.Left and Canvas.Top, like this
<Canvas Margin="100,0,0,0">
<Button x:Name="myButton"/>
<TextBlock Text="TextTextText" Canvas.Left="-40" Canvas.Top="60"/>
</Canvas>
You could actually have an CLR property calculating these two distances, based on your Button dimensions and perform binding to these two attached properties. For this situation, I set those values for the offsets for a Button dimension of (Width: 100, Height: 100).
PS. The code provided is working for UWP (I am more used to it :p), so I am not particularly 100% sure that the solution works right of the bat for WPF.
You could try rotating the button by 45 degrees like you did and then adding a TextBlock which is rotated -45 degrees to keep it horizontal. I'm sure there are better ways but this should work.
<Button>
<TextBlock Text="Testing">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-45"/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="45"/>
<TranslateTransform/>
</TransformGroup>
</Button.RenderTransform>
</Button>
Related
I want to create a template for a button, that will show an image (icon) instead of text.
I want to be able to assign different images to different instances of that button, for example:
<Button Style="{StaticResource iconButton}" ImageSource="Sources/icon.png">
or alternatively:
<Button Style="{StaticResource iconButton}">
<Image Source="...">
</Button>
(but I still want to be able to style the image in the template, so I wouldn't need to worry about color and size when I use it - so simply rendering the image as content won't do).
Example code:
Here I am using the image as a mask to render it in whatever color I want:
<Style TargetType="Button" x:Key="iconButton">
<Style.Resources>
<!-- add the "content to image source" converter-->
<converters:ContentToImageSourceConverter x:Key="ContentToImageSourceConverter"/>
</Style.Resources>
<Setter Property="Foreground" Value="{DynamicResource foreground_color}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Margin="5">
<Ellipse x:Name="circle" Width="45" Height="45" Fill="{DynamicResource foreground_color}" Opacity="0"/>
<Ellipse Width="45" Height="45" Fill="{DynamicResource foreground_color}">
<Ellipse.OpacityMask>
<!--How to accomplish this?-->
<ImageBrush ImageSource="{TemplateBinding Property=Content "/>
</Ellipse.OpacityMask>
</Ellipse>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="circle" Property="Opacity" Value="0.15"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="circle" Property="Opacity" Value="0.3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Have a look at the line where it says "how to accomplish this". I am using an image as a source but I want the image to be defined whenever you use the button, for example:
<Button Style="{StaticResource iconButton}" DockPanel.Dock="Right">
<Image Source="/Sources/settings_icon.png"/>
</Button>
I do not want to simply render the image as a content of the button because I'm using it as a mask for something else, thus I can change the foreground color and have the icons render in a different color.
I would do a custom control, with one dependency property of the image source. Have you tried this?
And then you will use it like this
<MyCustomButton DockPanel.Dock="Right" ImageSource = Sources/settings_icon.png">
</MyCustomButton>
The simplest way to do it:
Add UserControl to your project
In xaml just add one button
Add style to this control and set it to the button
Add dependency property, and link it to the image source (in style) by binding. Here you need also to have specified a source of binding.
{Binding RelativeSource={RelativeSource Self}}
Second way:
Make an class which is deriving form the Button class.
Add one dependency property, with the image source object.
In Style Specify a binding for the source property of the image control, it has to have the same name as he dependency property. I think that you will also need to specify the source of the binding as a Ancestor, because it could not be able to find the binding source.
Check here to see the syntax.
Binding to an ancestor in WPF
In both ways the usage will look same.
I was wondering if it is possible to insert my own bitmaps for scrollbar styling. I would like to to use an image for up/down arrows, background and scroller. This is what I have to start with, but I just don't know how to access these mentioned properties:
<TextBox Name="SlideNotes" Foreground="White" FontSize="20" FontWeight="Bold" Background="Transparent" BorderThickness="0" TextWrapping="Wrap" AcceptsReturn="True" ScrollViewer.VerticalScrollBarVisibility="Visible" Grid.Row="27" Grid.Column="11" Grid.ColumnSpan="46" Grid.RowSpan="5">
<TextBox.Resources>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Background" Value="Red"/>
</Style>
</TextBox.Resources>
I would appreciate any help.
You can use ImageBrush to set an image to any property that uses Brushes (Background, Foreground, BorderBrush, Fill, etc.).
In your case, you'd use it like this:
<TextBox Name="SlideNotes" Foreground="White" FontSize="20" FontWeight="Bold" Background="Transparent" BorderThickness="0" TextWrapping="Wrap" AcceptsReturn="True" ScrollViewer.VerticalScrollBarVisibility="Visible" Grid.Row="27" Grid.Column="11" Grid.ColumnSpan="46" Grid.RowSpan="5">
<TextBox.Resources>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="yourimage.jpg" Stretch="Fill" />
</Setter.Value>
</Setter>
</Style>
</TextBox.Resources>
</TextBox>
ImageBrush (and all other Brushes that inherit from TileBrush) has a set of properties that control how the image is shown. I've used Stretch="Fill" in my sample, which will make the image stretch to fill all the space available, but you could want it to behave differently.
For instance, this...
<ImageBrush ImageSource="yourimage.jpg" Stretch="None" TileMode="FlipXY" />
Will make your image repeat, with tiles alternatively flipped horizontally and/or vertically.
Toy around with Stretch and TileMode (or even ViewPort, ViewPortUnit, Viewbox and ViewboxUnit, if you feel brave enough) to get the effect you want.
EDIT - As with RepeatButton, the default ScrollBar template seems to pretty much ignore the Background property, most of the time, as well as other properties you could use for customization... This means you'll probably have to override the whole template to customize it to your liking.
Here's one ScrollBar template sample: ScrollBar Styles and Templates
And here's another for the RepeatButton: RepeatButton Styles and Templates
Looks like you're after a ControlTemplate. See here for a nice tutorial on how to style one.
To avoid having to style the entire ScrollViewer, you can instead style only the RepeatButton element, this will make things much easier to work with.
<Style TargetType="RepeatButton">
<Setter Property="Background" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
...
</Setter.Value>
</Setter>
</Style>
You may need to define this style in the Window Resources, instead of the TextBox resources due to the scope.
See the documentation for RepeatButton styles and templates.
I have a custom tooltip style that basically creates a nice black tooltip with an arrow pointing to the location of the item you hovered over.
The problem is that sometimes the tooltip will not always be placed in the correct location (i.e. near window edges) which means the tooltip arrow no longer points at the correct place... Is there anyway around this problem? Or can I create specific styles for each location placement?
<Style x:Key="{x:Type ToolTip}" TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<StackPanel>
<Border CornerRadius="3" HorizontalAlignment="Center" VerticalAlignment="Top" Padding="10,7" BorderThickness="0" Background="#e5323232">
<StackPanel>
<TextBlock FontFamily="Arial" FontSize="12" Text="{TemplateBinding Content}" Foreground="#f0f0f0" />
</StackPanel>
</Border>
<Path Margin="10,0,0,0" Fill="#e5323232" Data="M 0 0 L 6 6 L 12 0 Z"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
Maybe you could try this, I just set the Placement to Center and added a HorizontalOffset to match the arrow you created in the template.
However that wont center it vertically on the control, so you could make an IValueConverter and calculate the size of the control and divide by 2, or you could add a dummy element to your StackPanel that is the same size as the Border, and that should center the ToolTip without needing any code behind
<Style TargetType="{x:Type ToolTip}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Placement" Value="Center" />
<!--Offset to the arrow path-->
<Setter Property="HorizontalOffset" Value="15"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<StackPanel>
<Border x:Name="border" CornerRadius="3" HorizontalAlignment="Center" VerticalAlignment="Top" Padding="10,7" BorderThickness="0" Background="#e5323232">
<StackPanel>
<TextBlock FontFamily="Arial" FontSize="12" Text="{TemplateBinding Content}" Foreground="#f0f0f0" />
</StackPanel>
</Border>
<Path Margin="10,0,0,0" Fill="#e5323232" Data="M 0 0 L 6 6 L 12 0 Z"/>
<!--Dummy rectangle same height as tool tip, so it centers on the control-->
<Rectangle Height="{Binding ActualHeight, ElementName=border}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The simplest way of doing it is to use a UIElement that exists in the Control Tree as the PlacementTarget of the Tooltip. This will avoid the Silverlight automated positioning when you get near the window edges:
<StackPanel ToolTipService.ToolTip="{Binding Title, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"
ToolTipService.Placement="Bottom"
ToolTipService.PlacementTarget="{Binding ElementName=LayoutRoot}">
<TextBlock Text="{Binding Title,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
In this case the tooltip will be positioned always at the Origin of the LayoutRoot element. If you have a fixed path size and the PlacementTarget is always at the same position relative to the control for which you want to show the tooltip then this works fine.
If you need to position the Tooltip relatively to the control that triggers the Tooltip than you have to make the Path Data dynamic and calculate the distance to create a new Path Data in the Tooltip control every time the Tooltip is opened.
For this case you have to handle the Tooltip.IsOpened event and implement this logic. If you're using the PlacementTarget than you always know the direction relatively to your control so this makes it easier to calculate the Path vertices.
Another way which works but it's way more complex is to implement your own Popup that shows up when you move the mouse over your control. You would need to implement a few calculations to get the position of the popup relative to the Control, which is exactly what the Tooltip control does for you. The advantage of this is that you have complete control over the positioning of the tooltip and its appearance.
Some of you may have noticed that Office 2013 contains a new feature called touch mode.
And this is how it looks
I was wondering if i could achieve the same in WPF. Any ideas?
I just had to add something like this (code below) to my main grid. Thank you, HighCore for pointing me into the right direction.
<Grid.LayoutTransform>
<ScaleTransform x:Name="ApplicationScaleTransform"
CenterX="0"
CenterY="0"
ScaleX="1.2"
ScaleY="1.2" />
</Grid.LayoutTransform>
But how do I implement this in with the MVVM Pattern?
Sure, I could simply create an binding which bind ScaleX and ScaleY to an Property in my ViewModel.
But does it really belongs into the ViewModel? I mean this is clearly part of the GUI which should only be in the View.
EDIT:
Maybe I should bind ScaleX and ScaleY to an Property inside the XAML Codebehind (eg. MainWindow.xaml.cs) The problem is that the DataContext is already set to the ViewModel.
EDIT2 My Solution
The upper code snippet causes all elements to "grow". My problem with this code was that the fontsize of my textboxes was also affected. I managed to handle this unwanted behavior by defining a style for every element that should scale.
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<Style TargetType="ScrollBar">
<Setter Property="LayoutTransform" >
<Setter.Value>
<ScaleTransform x:Name="ApplicationScaleTransform"
CenterX="0"
CenterY="0"
ScaleX="{Binding ScaleFactor, UpdateSourceTrigger=PropertyChanged}"
ScaleY="{Binding ScaleFactor, UpdateSourceTrigger=PropertyChanged}"
/>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TabItem">
<Setter Property="LayoutTransform" >
<Setter.Value>
<ScaleTransform x:Name="ApplicationScaleTransform"
CenterX="0"
CenterY="0"
ScaleX="{Binding ScaleFactor, UpdateSourceTrigger=PropertyChanged}"
ScaleY="{Binding ScaleFactor, UpdateSourceTrigger=PropertyChanged}"
/>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Button">
<Setter Property="LayoutTransform" >
<Setter.Value>
<ScaleTransform x:Name="ApplicationScaleTransform"
CenterX="0"
CenterY="0"
ScaleX="{Binding ScaleFactor, UpdateSourceTrigger=PropertyChanged}"
ScaleY="{Binding ScaleFactor, UpdateSourceTrigger=PropertyChanged}"
/>
</Setter.Value>
</Setter>
</Style>
<ResourceDictionary.MergedDictionaries></ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Question: This code looks a bit ugly is there a way to define the same snippet for multiply target types? e.g.
I have a special ControlTemplate for some of my Buttons.
<ControlTemplate TargetType="{x:Type Button}">
<Path Name="ThePath" Fill="White" Stretch="UniformToFill"
Width="12" Height="12" Stroke="White"
StrokeThickness="4"
Data="M1.5,1.5 L10.5,10.5 M1.5,10.5 L10.5,1.5"/>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Fill" Value="#afa" TargetName="ThePath"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This works fine, but since I'm using a Path (in this case, it's just shaped like a fat X), exactly the path is clickable, not the small space between the corners of the X. Is there any automagic thing I can use to make the entire "block" of the X clickable?
I've considered wrapping the path in a rectangular object, but I'd just like to make sure I'm not missing something trivial.
Aviad P. is correct. This is what I do:
<Border Background="Transparent">
<Path ... />
</Border>
This works because when "hit testing" to determine where a mouse click should be routed, the "Transparent" brush is considered as if it was a regular color.