I need a thumb control that can be sized using a mouse. When the user hovers the mouse over one of the ends a size cursor should be displayed and when the user clicks and drags the end of the control it will be re-sized.
How can that be achieved?
Here is one I made a while ago, it allows Move and Resize, but you can remove the Move logic and it should work fine (the style is still a bit messy, but it works pretty well)
Its based on ContentControl so you can add any Element inside and Move/Resize on a Canvas, It uses 3 Adorners, one for Resize, one for Move and one to display information (current size)
Here is a full working example if you want to test/use/modify/improve :)
Code:
namespace WpfApplication21
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class ResizeThumb : Thumb
{
public ResizeThumb()
{
DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
}
private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Control designerItem = this.DataContext as Control;
if (designerItem != null)
{
double deltaVertical, deltaHorizontal;
switch (VerticalAlignment)
{
case VerticalAlignment.Bottom:
deltaVertical = Math.Min(-e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight);
designerItem.Height -= deltaVertical;
break;
case VerticalAlignment.Top:
deltaVertical = Math.Min(e.VerticalChange, designerItem.ActualHeight - designerItem.MinHeight);
Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaVertical);
designerItem.Height -= deltaVertical;
break;
default:
break;
}
switch (HorizontalAlignment)
{
case HorizontalAlignment.Left:
deltaHorizontal = Math.Min(e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth);
Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaHorizontal);
designerItem.Width -= deltaHorizontal;
break;
case HorizontalAlignment.Right:
deltaHorizontal = Math.Min(-e.HorizontalChange, designerItem.ActualWidth - designerItem.MinWidth);
designerItem.Width -= deltaHorizontal;
break;
default:
break;
}
}
e.Handled = true;
}
}
public class MoveThumb : Thumb
{
public MoveThumb()
{
DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
}
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Control designerItem = this.DataContext as Control;
if (designerItem != null)
{
double left = Canvas.GetLeft(designerItem);
double top = Canvas.GetTop(designerItem);
Canvas.SetLeft(designerItem, left + e.HorizontalChange);
Canvas.SetTop(designerItem, top + e.VerticalChange);
}
}
}
public class SizeAdorner : Adorner
{
private Control chrome;
private VisualCollection visuals;
private ContentControl designerItem;
protected override int VisualChildrenCount
{
get
{
return this.visuals.Count;
}
}
public SizeAdorner(ContentControl designerItem)
: base(designerItem)
{
this.SnapsToDevicePixels = true;
this.designerItem = designerItem;
this.chrome = new Control();
this.chrome.DataContext = designerItem;
this.visuals = new VisualCollection(this);
this.visuals.Add(this.chrome);
}
protected override Visual GetVisualChild(int index)
{
return this.visuals[index];
}
protected override Size ArrangeOverride(Size arrangeBounds)
{
this.chrome.Arrange(new Rect(new Point(0.0, 0.0), arrangeBounds));
return arrangeBounds;
}
}
}
Xaml:
<Window x:Class="WpfApplication21.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication21"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<local:MoveThumb Cursor="SizeAll">
<local:MoveThumb.Style>
<Style TargetType="{x:Type local:MoveThumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MoveThumb}">
<Rectangle Fill="Transparent" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:MoveThumb.Style>
</local:MoveThumb>
<Control x:Name="resizer">
<Control.Style>
<Style TargetType="{x:Type Control}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Control}">
<Grid>
<Grid Opacity="0" Margin="-3">
<local:ResizeThumb Height="3" Cursor="SizeNS" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<local:ResizeThumb Width="3" Cursor="SizeWE" VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="3" Cursor="SizeWE" VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
<local:ResizeThumb Height="3" Cursor="SizeNS" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
<local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNWSE" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNESW" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNESW" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="7" Height="7" Margin="-2" Cursor="SizeNWSE" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
<Grid IsHitTestVisible="False" Opacity="1" Margin="-3">
<Grid.Resources>
<Style TargetType="{x:Type Ellipse}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Stroke" Value="#FFC8C8C8" />
<Setter Property="StrokeThickness" Value=".5" />
<Setter Property="Width" Value="7" />
<Setter Property="Height" Value="7" />
<Setter Property="Margin" Value="-2" />
<Setter Property="Fill" Value="Silver" />
</Style>
</Grid.Resources>
<Rectangle SnapsToDevicePixels="True" StrokeThickness="1" Margin="1" Stroke="Black" StrokeDashArray="4 4"/>
<Ellipse HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Ellipse HorizontalAlignment="Right" VerticalAlignment="Top"/>
<Ellipse HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<Ellipse HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Control.Style>
</Control>
<Grid x:Name="sizeInfo" SnapsToDevicePixels="True">
<Path Stroke="Red" StrokeThickness="1" Height="10" VerticalAlignment="Bottom" Margin="-2,0,-2,-15" Stretch="Fill" Data="M0,0 0,10 M 0,5 100,5 M 100,0 100,10"/>
<TextBlock Text="{Binding Width}" Background="White" Padding="3,0,3,0" Foreground="Red" Margin="0,0,0,-18" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
<Path Stroke="Red" StrokeThickness="1" Width="10" HorizontalAlignment="Right" Margin="0,-2,-15,-2" Stretch="Fill" Data="M5,0 5,100 M 0,0 10,0 M 0,100 10,100"/>
<TextBlock Text="{Binding Height}" Background="White" Foreground="Red" Padding="3,0,3,0" Margin="0,0,-18,0" HorizontalAlignment="Right" VerticalAlignment="Center">
<TextBlock.LayoutTransform>
<RotateTransform Angle="90" CenterX="1" CenterY="0.5"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Grid>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="sizeInfo" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter TargetName="sizeInfo" Property="Visibility" Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Canvas>
<ContentControl Width="183" Height="110" Canvas.Left="166" Canvas.Top="50" />
</Canvas>
</Window>
Result:
With content inside (Button)
Sorry the cursors do not show when using SnipTool
Related
So I've been playing around with creating a custom title bar using WPF and this is what I have
<!--Add the WindowChrome object-->
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="34" />
</WindowChrome.WindowChrome>
<Window.Resources>
<ResourceDictionary>
<Style x:Key="CaptionButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="LayoutRoot" Background="Transparent" Width="44" Height="30">
<TextBlock x:Name="txt" Text="{TemplateBinding Content}" FontFamily="Segoe MDL2 Assets" FontSize="10"
Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"
RenderOptions.ClearTypeHint="Auto" TextOptions.TextRenderingMode="Aliased" TextOptions.TextFormattingMode="Display"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="#E5E5E5"/>
<Setter TargetName="txt" Property="Foreground" Value="#000000"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Minimize-->
<Style x:Key="MinimizeButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyle}">
<Setter Property="Content" Value=""/>
</Style>
<!--Maximize-->
<Style x:Key="MaximizeButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyle}">
<Setter Property="Content" Value=""/>
</Style>
<!--Restore-->
<Style x:Key="RestoreButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyle}">
<Setter Property="Content" Value=""/>
</Style>
<!--Close-->
<Style x:Key="CloseButtonStyle" TargetType="Button" BasedOn="{StaticResource CaptionButtonStyle}">
<Setter Property="Content" Value=""/>
</Style>
</ResourceDictionary>
</Window.Resources>
<!-- Title bar button commands -->
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Close" />
<CommandBinding Command="{x:Static SystemCommands.MaximizeWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Maximize" />
<CommandBinding Command="{x:Static SystemCommands.MinimizeWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Minimize" />
<CommandBinding Command="{x:Static SystemCommands.RestoreWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Restore" />
</Window.CommandBindings>
<Border x:Name="MainWindowBorder" BorderBrush="LightCoral" BorderThickness="0" >
<Grid x:Name="parentContainer" Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height ="Auto"/>
<RowDefinition Height ="*"/>
</Grid.RowDefinitions>
<!--Window chrome-->
<Grid Grid.Row="0" Height="30" Background="#F999">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
<!--App icon-->
<Image Source="/Resources/watermelon.ico" Width="18" Margin="2" HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBlock Text="Sweet App" FontFamily="Arial" Margin="4 3 0 0" />
</StackPanel>
<!--Caption buttons-->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
<Button Style="{StaticResource MinimizeButtonStyle}" WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="Minimize"
Command="{x:Static SystemCommands.MinimizeWindowCommand}"/>
<Button x:Name="RestoreButton" Visibility="Collapsed" Style="{StaticResource RestoreButtonStyle}"
Command="{x:Static SystemCommands.RestoreWindowCommand}" WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="Restore"/>
<Button x:Name="MaximizeButton" Visibility="Visible" Style="{StaticResource MaximizeButtonStyle}"
Command="{x:Static SystemCommands.MaximizeWindowCommand}" WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="Maximize" />
<Button Style="{StaticResource CloseButtonStyle}" WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="Close"
Command="{x:Static SystemCommands.CloseWindowCommand}"/>
</StackPanel>
</Grid>
<!--App content-->
<Grid Grid.Row="1" x:Name="AppArea">
<Path Data="M50,0L100,50 50,100 0,50z" Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2" />
</Grid>
</Grid>
</Border>
And that works great!
However if I were to comment out this part
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Close" />
<CommandBinding Command="{x:Static SystemCommands.MaximizeWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Maximize" />
<CommandBinding Command="{x:Static SystemCommands.MinimizeWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Minimize" />
<CommandBinding Command="{x:Static SystemCommands.RestoreWindowCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Restore" />
</Window.CommandBindings>
Then when I hover over the buttons (Minimize, Maximize and Close) they don't change color anymore and there are no obvious errors presented to me. And as far as I know, it shouldn't change anything UI related since the actual trigger for changing the button background is already defined above in the Window.Resources
Why is this happening?
Here's the code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
StateChanged += MainWindowStateChangeRaised;
}
// Can execute
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
// Minimize
private void CommandBinding_Executed_Minimize(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.MinimizeWindow(this);
}
// Maximize
private void CommandBinding_Executed_Maximize(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.MaximizeWindow(this);
}
// Restore
private void CommandBinding_Executed_Restore(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.RestoreWindow(this);
}
// Close
private void CommandBinding_Executed_Close(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.CloseWindow(this);
}
// State change
private void MainWindowStateChangeRaised(object sender, EventArgs e)
{
if (WindowState == WindowState.Maximized)
{
MainWindowBorder.BorderThickness = new Thickness(8);
RestoreButton.Visibility = Visibility.Visible;
MaximizeButton.Visibility = Visibility.Collapsed;
}
else
{
MainWindowBorder.BorderThickness = new Thickness(0);
RestoreButton.Visibility = Visibility.Collapsed;
MaximizeButton.Visibility = Visibility.Visible;
}
}
}
I want to change the icon on my button. Here is the xaml of my button:
<Button Name="InitPurgeBtn" Click="InitPurgeClick">
<Rectangle Width="35" Height="45" Margin="0,0,0,0">
<Rectangle.Fill>
<VisualBrush Stretch="Fill" Visual="{StaticResource InitIcon}" />
</Rectangle.Fill>
</Rectangle>
</Button>
The probleme is I don't know how to acces the Visual property of the Rectangle of my button in my controller to change "InitIcon" by "PurgeIcon"
All my icon are implement in xaml:
<Viewbox x:Key="ExtinctionIcon" Stretch="Uniform" x:Shared="False">
<Canvas Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="40" Height="40" Stretch="Fill" Fill="{Binding Foreground,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}"
Data="M15,24H17V22H15M16.56,{...}24H13V22H11M7,24H9V22H7V24Z"/>
</Canvas>
</Viewbox>
Edit :
I change my button and he is like this now :
<Button Name="InitBtn" Style="{StaticResource RoundButton}" Width="70" Height="70"
Click="InitPurgeClick" Content="{StaticResource InitIcon}">
</Button>
I want to change the icon in my code so I try to set Content property like this :
InitBtn.Content = "{StaticResource ExtinctionIcon}";
But this way just replace my icon with the string "StaticResource.."
Updated to reflect new information
You updated your question with some new information that changes things a lot.
Since you are trying to update Button.Content in code, you won't be able to use the MarkupExtension. MarkupExtensions (the stuff inside { } in the XAML) are only evaluated when the view is initially created. After that, they behave just like regular strings, so trying to set one in code won't work.
To set the value in code, you will need to manually do what the MarkupExtension is doing; find the resource by name, and set the value directly. You can do this with the following code (assuming a reference to InitPurgeBtn).
InitPurgeBtn.Content = InitPurgeBtn.FindResource("ExtinctionIcon");
Previous Answer
You should be able to add your icon to the Content of the Button directly, as it seems to be defined as a resource somewhere (because of the x:Key attribute). Your code doesn't show where exactly that is though, so I can't grantee this will work without some modification.
<Button Name="InitPurgeBtn"
Width="100"
Height="40"
Content="{StaticResource ExtinctionIcon}" />
In order for that to work the ExtinctionIcon resource will have to be defined someplace accessible to the button, meaning either in an ancestor of the button, or in App.xaml.
The fact that the resource is defined with x:Shared="false" seems to indicate that it was designed to be used in exactly this way, as that is required for visual elements that can possibly be hosted in multiple places simultaneously.
Alternatively, you could just copy and embed the icon directly in to the button.
<Button Name="InitPurgeBtn"
Click="InitPurgeClick">
<Viewbox Stretch="Uniform">
<Canvas Width="76"
Height="76"
Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="40"
Height="40"
Stretch="Fill"
Fill="{Binding Foreground,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType=Button}}"
Data="M15,24H17V22H15M16.56,{...}24H13V22H11M7,24H9V22H7V24Z"/>
</Canvas>
</Viewbox>
</Button>
You may use Content property.
<Button Name="InitPurgeBtn" Width="100" Height="40">
<Button.Content>
<Image Source=".\Icon.PNG"/>
</Button.Content>
</Button>
If you just want a single (xaml) icon, you can bind the content property of your button to your icon resource.
The control below gives an enhanced display - a xaml icon plus a text caption, including two colours for the icon and support for disabled state.
MyXamlIconHost.cs
public enum CaptionPosition { None, ToLeftOfIcon, AboveIcon, ToRightOfIcon, BelowIcon }
public enum IconSize { Small, Medium, Large, XLarge, XxLarge }
public class myXamlIconHost : Control
{
private static readonly Brush DefaultForeground = new SolidColorBrush(Color.FromRgb(32,32,32));
private static readonly Brush DefaultHighlight = Brushes.DarkOrange;
private static readonly Brush DefaultDisabledForeground = new SolidColorBrush(Color.FromRgb(192, 192, 192));
private static readonly Brush DefaultDisabledHighlight = new SolidColorBrush(Color.FromRgb(128, 128, 128));
static myXamlIconHost()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(myXamlIconHost), new FrameworkPropertyMetadata(typeof(myXamlIconHost)));
}
public FrameworkElement XamlIcon
{
get { return (FrameworkElement)GetValue(XamlIconProperty); }
set { SetValue(XamlIconProperty, value); }
}
public static readonly DependencyProperty XamlIconProperty =
DependencyProperty.Register("XamlIcon", typeof(FrameworkElement), typeof(myXamlIconHost), new PropertyMetadata(null));
public IconSize IconSize
{
get { return (IconSize)GetValue(IconSizeProperty); }
set { SetValue(IconSizeProperty, value); }
}
public static readonly DependencyProperty IconSizeProperty =
DependencyProperty.Register("IconSize", typeof(IconSize), typeof(myXamlIconHost), new PropertyMetadata(IconSize.Medium));
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(myXamlIconHost), new PropertyMetadata(null));
public CaptionPosition CaptionPosition
{
get { return (CaptionPosition)GetValue(CaptionPositionProperty); }
set { SetValue(CaptionPositionProperty, value); }
}
public static readonly DependencyProperty CaptionPositionProperty =
DependencyProperty.Register("CaptionPosition", typeof(CaptionPosition), typeof(myXamlIconHost), new PropertyMetadata(CaptionPosition.ToRightOfIcon));
public Brush StandardForeground
{
get { return (Brush)GetValue(StandardForegroundProperty); }
set { SetValue(StandardForegroundProperty, value); }
}
public static readonly DependencyProperty StandardForegroundProperty =
DependencyProperty.Register("StandardForeground", typeof(Brush), typeof(myXamlIconHost), new PropertyMetadata(DefaultForeground));
public Brush StandardHighlight
{
get { return (Brush)GetValue(StandardHighlightProperty); }
set { SetValue(StandardHighlightProperty, value); }
}
public static readonly DependencyProperty StandardHighlightProperty =
DependencyProperty.Register("StandardHighlight", typeof(Brush), typeof(myXamlIconHost), new PropertyMetadata(DefaultHighlight));
public Brush DisabledForeground
{
get { return (Brush)GetValue(DisabledForegroundProperty); }
set { SetValue(DisabledForegroundProperty, value); }
}
public static readonly DependencyProperty DisabledForegroundProperty =
DependencyProperty.Register("DisabledForeground", typeof(Brush), typeof(myXamlIconHost), new PropertyMetadata(DefaultDisabledForeground));
public Brush DisabledHighlight
{
get { return (Brush)GetValue(DisabledHighlightProperty); }
set { SetValue(DisabledHighlightProperty, value); }
}
public static readonly DependencyProperty DisabledHighlightProperty =
DependencyProperty.Register("DisabledHighlight", typeof(Brush), typeof(myXamlIconHost), new PropertyMetadata(DefaultDisabledHighlight));
}
// ==============================================================================================================================================
public class myXamlIconSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
const int defaultSize = 24;
if (!(value is IconSize))
return defaultSize;
var iconSizeValue = (IconSize)value;
switch (iconSizeValue)
{
case IconSize.Small:
return defaultSize * 2 / 3;
case IconSize.Large:
return defaultSize * 3 / 2;
case IconSize.XLarge:
return defaultSize * 2;
case IconSize.XxLarge:
return defaultSize * 5 / 2;
default:
return defaultSize;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
MyXamlIconHost.xaml
<Style TargetType="{x:Type ctrl:myXamlIconHost}">
<Setter Property="Focusable" Value="False" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ctrl:myXamlIconHost}">
<Grid Margin="{TemplateBinding Padding}">
<Grid.Resources>
<ctrl:myXamlIconSizeConverter x:Key="IconSizeConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="PART_CaptionTextBlock"
Grid.Row="1"
Grid.Column="0"
Margin="8,0,8,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{TemplateBinding StandardForeground}"
Text="{TemplateBinding Caption}" />
<!-- Set DataContext to "self" so that the Xaml Icon item can bind to the Foreground and BorderBrush properties -->
<ContentControl x:Name="PART_IconPresenter"
Grid.Row="1"
Grid.Column="1"
Width="{TemplateBinding IconSize,
Converter={StaticResource IconSizeConverter}}"
Height="{TemplateBinding IconSize,
Converter={StaticResource IconSizeConverter}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="{TemplateBinding StandardHighlight}"
Content="{TemplateBinding XamlIcon}"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Focusable="False"
Foreground="{TemplateBinding StandardForeground}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="PART_CaptionTextBlock" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisabledForeground}" />
<Setter TargetName="PART_IconPresenter" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisabledHighlight}" />
<Setter TargetName="PART_IconPresenter" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisabledForeground}" />
</Trigger>
<Trigger Property="CaptionPosition" Value="None">
<Setter TargetName="PART_CaptionTextBlock" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="CaptionPosition" Value="ToLeftOfIcon">
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Column" Value="0" />
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Row" Value="1" />
<Setter TargetName="PART_CaptionTextBlock" Property="Margin" Value="8,0,8,0" />
</Trigger>
<Trigger Property="CaptionPosition" Value="ToRightOfIcon">
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Column" Value="2" />
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Row" Value="1" />
<Setter TargetName="PART_CaptionTextBlock" Property="Margin" Value="8,0,8,0" />
</Trigger>
<Trigger Property="CaptionPosition" Value="AboveIcon">
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Column" Value="1" />
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Row" Value="0" />
<Setter TargetName="PART_CaptionTextBlock" Property="Margin" Value="8,0,8,4" />
</Trigger>
<Trigger Property="CaptionPosition" Value="BelowIcon">
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Column" Value="1" />
<Setter TargetName="PART_CaptionTextBlock" Property="Grid.Row" Value="2" />
<Setter TargetName="PART_CaptionTextBlock" Property="Margin" Value="8,4,8,0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
Example Usage
<Window ... >
<Window.Resources>
<Grid x:Key="TestIcon" x:Shared="False" Background="Transparent">
<Path Stretch="Fill" Data=" M 0,0 M 100,100 M 0,0 L 0,100 L 100,100 L 100,60 L 90,60 L 90,90 L 10,90 L 10,10 L 90,10 L 90,40 L 100,40 L 100,0 z" Fill="{ Binding Foreground, FallbackValue=Cyan}"/>
<Path Stretch="Fill" Data=" M 0,0 M 100,100 M 70,45 L 100,45 L 100,55 L 70,55 z" Fill="{ Binding BorderBrush, FallbackValue=Magenta}"/>
</Grid>
</Window.Resources>
<Button HorizontalAlignment="Center" VerticalAlignment="Center">
<Border Background="LightBlue">
<ctrls:myXamlIconHost Caption="The Caption" XamlIcon="{StaticResource TestIcon}" IconSize="XxLarge" Padding="20" />
</Border>
</Button>
</Window>
I want to show my GroupName on left and button "ShowOnly" on the right of header row.
I tried with this code but doesn't works.
Could anyone help me?
Thx
My code :
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Path=Name}" FontSize="18"></TextBlock>
<Button Style="{StaticResource ButtonStyle}" Content="Show Only" HorizontalAlignment="Right" Padding="15,0,15,0" Click="Button_Click"></Button>
</DockPanel>
</Expander.Header>
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Setter Property="Background" Value="#f0f0f5"></Setter>
<Setter Property="TextElement.FontFamily" Value="Arial Nova"/>
</Style>
</Expander.Style>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
My ButtonStyle :
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#66e0ff" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White" />
<Setter Property="Foreground" Value="#66e0ff" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I tried also with an DockPanel, but same result.
You need to set the HorizontalAlignment property of the ContentPresenter that is defined in the Expander's default control template to Stretch.
The easiest way to do this is probably to handle the Loaded event of the Expander and use a helper method that finds the ContentPresenter in the visual tree:
private void Expander_Loaded(object sender, RoutedEventArgs e)
{
Expander expander = sender as Expander;
System.Windows.Controls.Primitives.ToggleButton HeaderSite = GetChildOfType<System.Windows.Controls.Primitives.ToggleButton>(expander);
if (HeaderSite != null)
{
ContentPresenter cp = GetChildOfType<ContentPresenter>(HeaderSite);
if (cp != null)
cp.HorizontalAlignment = HorizontalAlignment.Stretch;
}
}
private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
<Expander IsExpanded="True" Loaded="Expander_Loaded">
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch">
<Button Style="{StaticResource ButtonStyle}" Content="Show Only" DockPanel.Dock="Right" Padding="15,0,15,0" Click="Button_Click"></Button>
<TextBlock Text="{Binding Path=Name}" FontSize="18"></TextBlock>
</DockPanel>
</Expander.Header>
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Setter Property="Background" Value="#f0f0f5"></Setter>
<Setter Property="TextElement.FontFamily" Value="Arial Nova"/>
</Style>
</Expander.Style>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
Set width of DockPanel to width of expander so that it will stretch properly.
<DockPanel HorizontalAlignment="Stretch" Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Expander}}, Path=ActualWidth}">
You can refer to these solutions:
https://joshsmithonwpf.wordpress.com/2007/02/24/stretching-content-in-an-expander-header/
I create a RangeSlider control:
XAML:
<Style x:Key="RangeSliderRepeatButton" TargetType="{x:Type RepeatButton}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Background="Transparent" Height="6" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RangeSliderThumbStyle" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Grid Margin="0,0,0,10">
<Label x:Name="PART_ValueOfSlider" Content="{Binding Value, RelativeSource={RelativeSource AncestorType={x:Type Slider}}}"
Margin="0 -20 0 0"
HorizontalAlignment="Center"
Foreground="Red"/>
<Path x:Name="PART_Rectangle" Fill="Gray">
<Path.Data>
<RectangleGeometry Rect="0,0 10 9" RadiusX="2" RadiusY="2"></RectangleGeometry>
</Path.Data>
<Path.Effect>
<DropShadowEffect ShadowDepth="2" BlurRadius="3" Color="Black" Opacity="0.4" Direction="270" />
</Path.Effect>
</Path>
<Path x:Name="PART_Traingle" Data="M 0 8 L 5 14 L 10 8 Z" Fill="Gray" >
<Path.Effect>
<DropShadowEffect ShadowDepth="1" BlurRadius="0" Color="Black" Opacity="0.4" Direction="270" />
</Path.Effect>
</Path>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PART_Rectangle" Property="Fill" Value="{DynamicResource LabledSliderThumbHoverBrush}" />
<Setter TargetName="PART_Traingle" Property="Fill" Value="{DynamicResource LabledSliderThumbHoverBrush}" />
</Trigger>
<Trigger Property="IsMouseCaptured" Value="True">
<Setter TargetName="PART_Rectangle" Property="Fill" Value="{DynamicResource LabledSliderThumbFocusesBrush}" />
<Setter TargetName="PART_Traingle" Property="Fill" Value="{DynamicResource LabledSliderThumbFocusesBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RangeSlider" TargetType="{x:Type Slider}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Slider}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="{TemplateBinding MinWidth}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Track Grid.Column="0" x:Name="PART_Track">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource RangeSliderRepeatButton}" Command="Slider.DecreaseLarge" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="PART_Thumb" Style="{StaticResource RangeSliderThumbStyle}"/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource RangeSliderRepeatButton}" Command="Slider.IncreaseLarge" />
</Track.IncreaseRepeatButton>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Grid x:Name="LayoutRoot" Background="#FF878889">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="47*"/>
<ColumnDefinition Width="353*"/>
</Grid.ColumnDefinitions>
<Border VerticalAlignment="Center"
BorderBrush="Black"
Background="Black"
Height="10"
Grid.Column="0"
BorderThickness="1"
Padding="2"
CornerRadius="4" Grid.ColumnSpan="2" Margin="0,5"/>
<Border x:Name="progressBorder"
SnapsToDevicePixels="True"
Background="Blue"
BorderBrush="Blue"
Height="6"
VerticalAlignment="Center" Grid.ColumnSpan="2" Margin="0,7"
/>
<Slider x:Name="LowerSlider"
Minimum="{Binding RelativeSource={RelativeSource AncestorType=local:RangeSlider}, Path=Minimum, Mode=TwoWay}"
Maximum="{Binding RelativeSource={RelativeSource AncestorType=local:RangeSlider}, Path=Maximum, Mode=TwoWay}"
Value="{Binding RelativeSource={RelativeSource AncestorType=local:RangeSlider}, Path=LowerValue, Mode=TwoWay}"
Style="{StaticResource SliderStyle}" Grid.ColumnSpan="2" />
<Slider x:Name="UpperSlider"
Minimum="{Binding RelativeSource={RelativeSource AncestorType=local:RangeSlider}, Path=Minimum, Mode=TwoWay}"
Maximum="{Binding RelativeSource={RelativeSource AncestorType=local:RangeSlider}, Path=Maximum, Mode=TwoWay}"
Value="{Binding RelativeSource={RelativeSource AncestorType=local:RangeSlider}, Path=UpperValue, Mode=TwoWay}"
Style="{StaticResource SliderStyle}" Grid.Column="1" />
</Grid>
RangeSlider.cs
public partial class RangeSlider : UserControl
{
public RangeSlider()
{
this.InitializeComponent();
this.LayoutUpdated += new EventHandler(RangeSlider_LayoutUpdated);
}
void RangeSlider_LayoutUpdated(object sender, EventArgs e)
{
SetProgressBorder();
}
private void SetProgressBorder()
{
double lowerPoint = (this.ActualWidth * (LowerValue - Minimum)) / (Maximum - Minimum);
double upperPoint = (this.ActualWidth * (UpperValue - Minimum)) / (Maximum - Minimum);
upperPoint = this.ActualWidth - upperPoint;
progressBorder.Margin = new Thickness(lowerPoint, 0, upperPoint, 0);
}
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public double LowerValue
{
get { return (double)GetValue(LowerValueProperty); }
set { SetValue(LowerValueProperty, value); }
}
public double UpperValue
{
get { return (double)GetValue(UpperValueProperty); }
set { SetValue(UpperValueProperty, value); }
}
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register("Minimum", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(0d, new PropertyChangedCallback(PropertyChanged)));
public static readonly DependencyProperty LowerValueProperty =
DependencyProperty.Register("LowerValue", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(10d, new PropertyChangedCallback(PropertyChanged)));
public static readonly DependencyProperty UpperValueProperty =
DependencyProperty.Register("UpperValue", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(90d, new PropertyChangedCallback(PropertyChanged)));
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register("Maximum", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(100d, new PropertyChangedCallback(PropertyChanged)));
private static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RangeSlider slider = (RangeSlider)d;
if (e.Property == RangeSlider.LowerValueProperty)
{
slider.UpperSlider.Value = Math.Max(slider.UpperSlider.Value, slider.LowerSlider.Value);
}
else if (e.Property == RangeSlider.UpperValueProperty)
{
slider.LowerSlider.Value = Math.Min(slider.UpperSlider.Value, slider.LowerSlider.Value);
}
slider.SetProgressBorder();
}
}
It work fine when Label x:Name="PART_ValueOfSlider"contain small value.
When Label x:Name="PART_ValueOfSlider" has big value, ProgressBorder display show not as I expected
How to set ProgressBorder work fine? Thanks for help me !!!
I am using one slider Just Like You But Its work fine for me The Xaml code for the Slider
<ControlTemplate x:Key="TimeRangeSliderTemplate" TargetType="{x:Type Slider}">
<StackPanel>
<Border SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle x:Name="PART_SelectionRange"/>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.Thumb>
<Thumb x:Name="Thumb">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Rectangle Fill="Red"
Stroke="Black"
StrokeThickness="1"
Width="10"
Height="18"
SnapsToDevicePixels="True"/>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track.Thumb>
</Track>
</Grid>
</Border>
</StackPanel>
</ControlTemplate>
<Style TargetType="{x:Type sliders:TimeRangeSlider}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type sliders:TimeRangeSlider}">
<Grid VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ElementName=Part_LowerSlider,Path=Value}" Foreground="Red" VerticalAlignment="Top" Margin="{Binding ElementName=Part_SelectedRect,Path=Margin}"/>
<TextBlock x:Name="PART_RIGHTTHUMPVALUE" Text="{Binding ElementName=Part_UpperSlider,Path=Value}" Foreground="Red" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</StackPanel>
<Grid Grid.Row="1">
<Border BorderThickness="0,1,0,0" BorderBrush="Black" VerticalAlignment="Center" Height="1" Margin="5,0,5,0"/>
<Rectangle x:Name="Part_SelectedRect" Fill="Green" Height="10" HorizontalAlignment="Left"/>
<Slider x:Name="Part_LowerSlider"
Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding LowerValue}"
Template="{StaticResource TimeRangeSliderTemplate}"
Margin="0,0,0,0"/>
<Slider x:Name="Part_UpperSlider"
Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding UpperValue}"
Template="{StaticResource TimeRangeSliderTemplate}"
Margin="0,0,0,0"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And here is the Cs file of the Xaml
public class TimeRangeSlider : Control
{
private const string PartName_LowerSlider = "Part_LowerSlider";
private const string PartName_UpperSlider = "Part_UpperSlider";
private const string PartName_SelectedRegion = "Part_SelectedRect";
private const string PART_RIGHTTHUMPVALUE = "PART_RIGHTTHUMPVALUE";
private Slider lowerSlider;
private Slider upperSlider;
Rectangle selectedRect;
TextBlock rightText;
public TimeRangeSlider()
{
this.DefaultStyleKey = typeof(TimeRangeSlider);
this.Loaded += TimeRangeSlider_Loaded;
}
void TimeRangeSlider_Loaded(object sender, RoutedEventArgs e)
{
lowerSlider.ValueChanged += LowerSlider_ValueChanged;
upperSlider.ValueChanged += UpperSlider_ValueChanged;
lowerSlider.Minimum = Minimum;
lowerSlider.Maximum = Maximum;
lowerSlider.Value = LowerValue;
upperSlider.Minimum = Minimum;
upperSlider.Maximum = Maximum;
upperSlider.Value = UpperValue;
SetView();
}
public override void OnApplyTemplate()
{
lowerSlider = this.GetTemplateChild(PartName_LowerSlider) as Slider;
upperSlider = this.GetTemplateChild(PartName_UpperSlider) as Slider;
selectedRect = this.GetTemplateChild(PartName_SelectedRegion) as Rectangle;
rightText = this.GetTemplateChild(PART_RIGHTTHUMPVALUE) as TextBlock;
base.OnApplyTemplate();
}
private void LowerSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
upperSlider.Value = Math.Max(upperSlider.Value, lowerSlider.Value);
SetView();
}
private void UpperSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
lowerSlider.Value = Math.Min(upperSlider.Value, lowerSlider.Value);
SetView();
}
private void SetView()
{
LowerValue = lowerSlider.Value;
UpperValue = upperSlider.Value;
var unit = lowerSlider.ActualWidth / Maximum;
var leftMargin = LowerValue * unit;
if (UpperValue > LowerValue)
{
var width = (UpperValue - LowerValue) * unit;
selectedRect.Width = width;
}
selectedRect.Margin = new Thickness(leftMargin, 0, 0, 0);
rightText.Margin = new Thickness(selectedRect.Width-20, 0, 0, 0);
}
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register("Minimum", typeof(double), typeof(TimeRangeSlider), new UIPropertyMetadata(0d));
public double LowerValue
{
get { return (double)GetValue(LowerValueProperty); }
set { SetValue(LowerValueProperty, value); }
}
public static readonly DependencyProperty LowerValueProperty =
DependencyProperty.Register("LowerValue", typeof(double), typeof(TimeRangeSlider), new UIPropertyMetadata(0d));
public double UpperValue
{
get { return (double)GetValue(UpperValueProperty); }
set { SetValue(UpperValueProperty, value); }
}
public static readonly DependencyProperty UpperValueProperty =
DependencyProperty.Register("UpperValue", typeof(double), typeof(TimeRangeSlider), new UIPropertyMetadata(0d));
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register("Maximum", typeof(double), typeof(TimeRangeSlider), new UIPropertyMetadata(1d));
}
and the usage of the control
<SliderControl:TimeRangeSlider x:Name="slider"
Margin="10"
LowerValue="30"
UpperValue="70"
Minimum="0"
Maximum="100"
/>
Elements in canvas will not influence for measure. So, use code:
<Canvas>
<Label x:Name="PART_ValueOfSlider" Content="{Binding Value, RelativeSource={RelativeSource AncestorType={x:Type Slider}}}"
Margin="0 0 0 0"
HorizontalAlignment="Center"
Foreground="Red">
<Label.RenderTransform>
<ScaleTransform ScaleY="-1" />
</Label.RenderTransform>
<Label.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleY="-1" />
</TransformGroup>
</Label.LayoutTransform>
</Label>
</Canvas>
All, I have the following resources which defines a custom CheckBox and the images to use for the checked/un-checked states.
<sys:String x:Key="Up">
F1 M 37.8516,35.625L 34.6849,38.7917L 23.6016,50.2708L
23.6016,39.9792L 37.8516,24.9375L 52.1016,39.9792L 52.1016,
50.2708L 41.0182,38.7917L 37.8516,35.625 Z
</sys:String>
<sys:String x:Key="Down">
F1 M 37.8516,39.5833L 52.1016,24.9375L 52.1016,35.2292L
37.8516,50.2708L 23.6016,35.2292L 23.6016,24.9375L 37.8516,39.5833 Z
</sys:String>
<Style x:Key="styleCustomCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Path x:Name="MyPin" Width="18" Height="18" Stretch="Fill" Fill="#FF000000"
Data="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOnData)}" />
<ContentPresenter VerticalAlignment="Center" Margin="10,0,0,0" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="MyPin" Property="Data"
Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOffData)}" />
<Setter TargetName="MyPin" Property="Fill" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Where this is used as follows
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Background="Beige">
<CheckBox Height="35"
local:CustomCheckBoxClass.IsCheckedOnData="{StaticResource Up}"
local:CustomCheckBoxClass.IsCheckedOffData="{StaticResource Down}"
Style="{StaticResource styleCustomCheckBox}"
Content="MySolution1" />
<CheckBox Height="35"
local:CustomCheckBoxClass.IsCheckedOnData="{StaticResource Up}"
local:CustomCheckBoxClass.IsCheckedOffData="{StaticResource Down}"
Style="{StaticResource styleCustomCheckBox}"
Content="MySolution2" />
</StackPanel>
I use the following DependencyPropertys to support this
public class CustomCheckBoxClass : DependencyObject
{
public static readonly DependencyProperty IsCheckedOnDataProperty;
public static void SetIsCheckedOnData(DependencyObject DepObject, string value)
{
DepObject.SetValue(IsCheckedOnDataProperty, value);
}
public static string GetIsCheckedOnData(DependencyObject DepObject)
{
return (string)DepObject.GetValue(IsCheckedOnDataProperty);
}
public static readonly DependencyProperty IsCheckedOffDataProperty;
public static void SetIsCheckedOffData(DependencyObject DepObject, string value)
{
DepObject.SetValue(IsCheckedOffDataProperty, value);
}
public static string GetIsCheckedOffData(DependencyObject DepObject)
{
return (string)DepObject.GetValue(IsCheckedOffDataProperty);
}
static CustomCheckBoxClass()
{
PropertyMetadata MyPropertyMetadata = new PropertyMetadata(string.Empty);
IsCheckedOnDataProperty = DependencyProperty.RegisterAttached(
"IsCheckedOnData", typeof(string), typeof(CustomCheckBoxClass), MyPropertyMetadata);
IsCheckedOffDataProperty = DependencyProperty.RegisterAttached(
"IsCheckedOffData", typeof(string), typeof(CustomCheckBoxClass), MyPropertyMetadata);
}
}
Now I want to know how to extend this so I can use more detailed vector graphics. I have some graphics created using Expression Design and I have exported these as XAML files. The mark up for one of these files is
<DrawingBrush x:Key="Layer_1" Stretch="Uniform">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FF565656" Geometry="M 107.455,171.715L 107.455,29.3347L 220.225,29.3347L 220.225,171.715L 107.455,171.715 Z "/>
<GeometryDrawing Brush="#FF565656" Geometry="F1 M 152.5,298.345L 152.5,201.955L 175.18,201.955L 175.18,298.345L 152.5,298.345 Z "/>
<GeometryDrawing Brush="#FFFFFFFF" Geometry="M 124.15,172.975L 124.15,48.8647L 165.73,48.8647L 165.73,172.975L 124.15,172.975 Z "/>
<GeometryDrawing Brush="#FF565656" Geometry="F1 M 83.1999,208.885L 83.1999,162.895L 244.48,162.895L 244.48,208.885L 83.1999,208.885 Z "/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
How can I include this in a resource dictionary that can be used directly in a Window/Component? I have attempted to change the DependencyProperty to provide access to DrawingBrush and I have changed the XAML to
<CheckBox Height="35"
local:CustomCheckBoxClass.IsCheckedOnData="{StaticResource Layer_1}"
local:CustomCheckBoxClass.IsCheckedOffData="{StaticResource Down}"
Style="{StaticResource styleCustomCheckBox}"
Content="MySolution1" />
Where I reference the relevant ResourceDictionary, but this has not worked.
Thanks for your time.
Edit. based on #HighCore's comment. Lets say I have the following customised Checkbox
<Style x:Key="MheckBox"
TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Image x:Name="imageCheckBox"
Width="16"
Height="16"
Source="F:\Camus\ResourceStudio\Graphics\Images\UnPinned16.png"/>
<ContentPresenter VerticalAlignment="Center"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="imageCheckBox"
Property="Source"
Value="F:\Camus\ResourceStudio\Graphics\Images\Pinned16.png"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="imageCheckBox"
Property="Source"
Value="F:\Camus\ResourceStudio\Graphics\Images\UnPinned16.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
which works great. How can I change the Value="F:\Camus\ResourceStudio\Graphics\Images\UnPinned16.png" to use the vector graphics I have outlined above?
The fact, that the in Template is used to Path and it assumes a string value in the Data parameter. But now you use DrawingBrush, usually it is used for Rectangle control.
So, we change the type of attached depending properties on the type of DrawingBrush:
public static readonly DependencyProperty IsCheckedOnDataProperty;
public static void SetIsCheckedOnData(DependencyObject DepObject, DrawingBrush value)
{
DepObject.SetValue(IsCheckedOnDataProperty, value);
}
public static DrawingBrush GetIsCheckedOnData(DependencyObject DepObject)
{
return (DrawingBrush)DepObject.GetValue(IsCheckedOnDataProperty);
}
static CustomCheckBoxClass()
{
PropertyMetadata MyPropertyMetadata = new PropertyMetadata(null);
IsCheckedOnDataProperty = DependencyProperty.RegisterAttached("IsCheckedOnData",
typeof(DrawingBrush),
typeof(CustomCheckBoxClass),
MyPropertyMetadata);
}
In Style, now change the Path on the Rectangle, like this:
<Style x:Key="styleCustomCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Rectangle Width="16" Height="16"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOnData)}" />
<ContentPresenter VerticalAlignment="Center" Margin="10,0,0,0" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="MyRectangle" Property="Fill" Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(local:CustomCheckBoxClass.IsCheckedOffData)}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>