WPF Change a property in a customcontrol after a button click - wpf

I posted a question in this link. maybe I'm not well expressed.
It's very simple, I want to change a property in a usercontrol or CustomControl after a click on a Boutton outside...
The code of the customcontrol is as follows :
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border x:Name="container" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Hidden" Value="true">
<Setter Property="BorderBrush" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
public bool Hidden
{
get { return (bool)GetValue(HiddenProperty); }
set { SetValue(HiddenProperty, value); }
}
// Using a DependencyProperty as the backing store for Hidder. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HiddenProperty =
DependencyProperty.Register("Hidden", typeof(bool), typeof(CustomControl1), new PropertyMetadata(false));
}
And a simple window for test
<Window x:Class="WpfTestCustomControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomBorder;assembly=WpfCustomBorder"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="400"/>
<ColumnDefinition Width="70"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<local:CustomControl1 x:Name="cc" BorderBrush="Red" BorderThickness="3" Margin="10" Grid.RowSpan="2"/>
<Button Grid.Column="1" Content="Ok" Margin="5" Click="Button_Click"/>
</Grid>
namespace WpfTestCustomControl
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
cc.Hidden = true;
}
}
}
The property "Hidden" is a dependency property inside the custom control.
When i click on the button in mainwindow i want to change the hidden property to true. this must fire the trigger inside the custom control to change borderbrush to "blue" color. While nothing happen.
Is there something missing or is not the right way to do it ?
Thanks in advance..

Don't hard-set BorderBrush="Red" in your Control's declaration, it's prioritary over any trigger's setter.
You might want to check msdn's Dependency Property Value Precedence

Related

How to set a property of a custom control from the main window?

I have a custom control, this is the generic.axml code:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Calendario"
xmlns:MyNamespace="clr-namespace:Calendario;assembly=Calendario"
xmlns:Converters="clr-namespace:Calendario.Converters">
<Converters:DateConverter x:Key="DateConverter"></Converters:DateConverter>
<Converters:DayBorderColorConverter x:Key="DayBorderColorConverter"></Converters:DayBorderColorConverter>
<Style TargetType="{x:Type local:CalendarioPersonalizado}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CalendarioPersonalizado}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<TextBlock Text="{Binding Date}" />
<Grid Height="30" DockPanel.Dock="Top">
</Grid>
<ItemsControl ItemsSource="{Binding Days}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="{Binding ColorRecuadroExterno, Mode=TwoWay}" BorderThickness="1" Padding="0">
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And I have my Calendario.cs with the dpendency property:
public static readonly DependencyProperty ColorRecuadroExternoProperty = DependencyProperty.Register("ColorRecuadroExterno", typeof(Brush), typeof(CalendarioPersonalizado));
public Brush ColorRecuadroExterno
{
get { return (Brush)GetValue(ColorRecuadroExternoProperty); }
set { SetValue(ColorRecuadroExternoProperty, value); }
}
And later in my main windows I use the control:
<local:CalendarioPersonalizado x:Name="cCalendario" ColorRecuadroExterno="Green"/>
The problem is that the border of the day in the calendar is not set to green like I have tried to set in the main window.
Also in the code behid I have tried this:
cCalendario.ColorRecuadroExterno = System.Windows.Media.Brushes.Green;
But the the color is not set.
What I want to do is set the color of the border in my custom cotrol from my main application.
Thanks.
If you put a Callback method in your local:CalendarioPersonalizado class and set your backround in this callback method. I think it is going to work.
public static readonly DependencyProperty ColorRecuadroExternoProperty = DependencyProperty.Register("ColorRecuadroExterno", typeof(Brush), typeof(CalendarioPersonalizado),
new PropertyMetadata(Brushes.Brown, Callback));
private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CalendarioPersonalizado obj = d as CalendarioPersonalizado;
obj.ColorRecuadroExterno.Background = (Brush)e.NewValue;
}
Your DependencyProperty is of type Brush. You can't implicitly convert "Green" to a Brush.
You either need to use a converter to convert a string representation of a color to a brush, or make your property type Color, and bind it to an appropriate property.

WPF TemplateBinding to an ObservableCollection

I'm creating a content control that contains another usercontrol. We'll call them InnerControl and OuterControl. The InnerControl has a dependency property of type ObservableCollection called "Items." I'm trying to bind that to an identical Dependency Property in the OuterControl. Here is a stub of the InnerControl code:
public class InnerControl : UserControl {
public InnerControl() {
InnerItems = new ObservableCollection<string>();
}
public ObservableCollection<string> InnerItems
{
get { return (ObservableCollection<string>)GetValue(InnerItemsProperty); }
set { SetValue(InnerItemsProperty, value); }
}
public static DependencyProperty InnerItemsProperty =
DependencyProperty.Register("InnerItems",
typeof(ObservableCollection<string>),
typeof(InnerControl),
new PropertyMetadata());
}
The outer control contains an identical Items property:
public class OuterControl : ContentControl {
public OuterControl() {
OuterItems = new ObservableCollection<string>();
}
static OuterControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(OuterControl),
new FrameworkPropertyMetadata(typeof(OuterControl)));
}
public ObservableCollection<string> OuterItems
{
get { return (ObservableCollection<string>)GetValue(OuterItemsProperty); }
set { SetValue(OuterItemsProperty, value); }
}
public static DependencyProperty OuterItemsProperty =
DependencyProperty.Register("OuterItems",
typeof(ObservableCollection<string>),
typeof(OuterControl),
new PropertyMetadata());
}
Then I'm defining the OuterControl's appearance in the generic.xaml file:
<Style TargetType="{x:Type userControls:OuterControl}">
<Setter Property="Padding" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type userControls:OuterControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<local:InnerControl Grid.Row="0" Grid.Column="0"
InnerItems="{TemplateBinding OuterItems}"/>
<ContentPresenter Grid.Row="1" Grid.Column="0"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The really important part of the above code I want to call your attention to is:
<local:InnerControl Grid.Row="0" Grid.Column="0"
InnerItems="{TemplateBinding OuterItems}"/>
What I expect to happen is that when items are added to the OuterItems collection of the OuterControl, those same items will be added to the InnerControl.InnerItems collection. However, that doesn't happen, and I can't figure out why.
I've also tried a relative binding so that I could experiment with using TwoWay mode and so on. Something like this:
InnerItems="{Binding OuterItems, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"
But so far that hasn't worked either.
UPDATE
Everything that I thought solved this problem so far has only exposed new problems, so I've removed my previous updates. What I'm stuck with at this point is:
If I initialize InnerItems in the constructor, then the TemplateBinding doesn't seem to work (the items never get updated)
If I don't initialize InnerItems at all, the TemplateBinding works. However, if InnerControl is just used by itself in the Designer, it breaks, because InnerItems is null when the designer tries to add items to it.
When you have a collection type dependency property, you must not use an instance of the collection class as default value of the property. Doing so will make all instances of the control that owns the property use the same collection instance.
So your property metadata
new PropertyMetadata(new ObservableCollection<string>())
should be replaced by
new PropertyMetadata(null)
or you do not specify any metadata at all
public static DependencyProperty InnerItemsProperty =
DependencyProperty.Register(
"InnerItems", typeof(ObservableCollection<string>), typeof(InnerControl));
Now you would somehow have to initialize the property value. As usual, you'll do it in the control's constructor, like
public InnerControl()
{
InnerItems = new ObservableCollection<string>();
}
When you now bind the property of the control like
<local:InnerControl InnerItems="{Binding ...}" />
the value set in the constructor is replaced by the value produced by the Binding.
However, this does not happen when you create the Binding in a Style Setter, because values from Style Setters have lower precedence than so-called local values (see Dependency Property Value Precedence).
A workaround is to set the default value by the DependencyObject.SetCurrentValue() method, which does not set a local value:
public InnerControl()
{
SetCurrentValue(InnerItemsProperty, new ObservableCollection<string>());
}
I find it quite likely that #Clemens comment has the right answer. Anyhow, I tested your solution using the code below and it worked fine for me.
Check how you are binding and adding items. You did not post that code in your question.
OuterControl
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace TemplateBindingTest.Controls
{
public class OuterControl : UserControl
{
static OuterControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(OuterControl), new FrameworkPropertyMetadata(typeof(OuterControl)));
}
public ObservableCollection<string> OuterItems
{
get { return (ObservableCollection<string>)GetValue(OuterItemsProperty); }
set { SetValue(OuterItemsProperty, value); }
}
public static DependencyProperty OuterItemsProperty =
DependencyProperty.Register("OuterItems",
typeof(ObservableCollection<string>),
typeof(OuterControl),
new PropertyMetadata(new ObservableCollection<string>()));
}
}
InnerControl
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace TemplateBindingTest.Controls
{
public class InnerControl : UserControl
{
static InnerControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(InnerControl), new FrameworkPropertyMetadata(typeof(InnerControl)));
}
public ObservableCollection<string> InnerItems
{
get { return (ObservableCollection<string>)GetValue(InnerItemsProperty); }
set { SetValue(InnerItemsProperty, value); }
}
public static DependencyProperty InnerItemsProperty =
DependencyProperty.Register("InnerItems",
typeof(ObservableCollection<string>),
typeof(InnerControl),
new PropertyMetadata(new ObservableCollection<string>()));
}
}
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:TemplateBindingTest.Controls">
<Style TargetType="{x:Type controls:OuterControl}">
<Setter Property="Padding" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:OuterControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" Grid.Column="0"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
<ItemsControl Grid.Row="1" ItemsSource="{TemplateBinding OuterItems}" />
<Border Grid.Row="2" BorderThickness="1" BorderBrush="Red">
<controls:InnerControl Grid.Column="0"
InnerItems="{TemplateBinding OuterItems}">Inner Control</controls:InnerControl>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:InnerControl}">
<Setter Property="Padding" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:InnerControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" Grid.Column="0"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
<ItemsControl Grid.Row="1" ItemsSource="{TemplateBinding InnerItems}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainWindow.xaml
<Window x:Class="TemplateBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:TemplateBindingTest.Controls"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:OuterControl OuterItems="{Binding OuterItems}">Outer Control</controls:OuterControl>
<Button Grid.Row="1" Content="Add" Click="Button_Click" HorizontalAlignment="Left" />
</Grid>
</Window>
MainWindow.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
namespace TemplateBindingTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<string> _OuterItems;
public MainWindow()
{
InitializeComponent();
DataContext = this;
_OuterItems = new ObservableCollection<string>(new List<string>()
{
"Test 1",
"Test 2",
"Test 3",
});
}
public ObservableCollection<string> OuterItems
{
get
{
return _OuterItems;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_OuterItems.Add(System.IO.Path.GetRandomFileName());
}
}
}

Control inheritance and blendability

I created a custom control which inherits from Window. The goal is to make a reusable window for all the small apps I'll program in my company, and not having to redo the header/footer/base styles... each time.
So here is what I did.
The class:
public class MyWindow : Window
{
public bool ShowHeader
{
get { return (bool)GetValue(ShowHeaderProperty); }
set { SetValue(ShowHeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for ShowHeader. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ShowHeaderProperty =
DependencyProperty.Register("ShowHeader", typeof(bool), typeof(MyWindow), new PropertyMetadata(true));
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
// Using a DependencyProperty as the backing store for HeaderText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderTextProperty =
DependencyProperty.Register("HeaderText", typeof(string), typeof(MyWindow), new PropertyMetadata(""));
public MyWindow()
{
this.Template = FindResource("MyWindowTemplate") as ControlTemplate;
}
}
The template:
<ControlTemplate x:Key="MyWindowTemplate" TargetType="{x:Type me:MyWindow}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="Images/logo.gif" />
<TextBlock Grid.Column="1" Text="{TemplateBinding HeaderText}" />
</Grid>
<ContentPresenter />
</DockPanel>
</Border>
</ControlTemplate>
Those 2 things are in a class library.
In my app, I have set this.
app.xaml:
<Application x:Class="TestInheritance.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/ClassLibrary1;component/MyStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
and my MainWindow.xaml is:
<uc:MyWindow x:Class="TestInheritance.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:ClassLibrary1;assembly=ClassLibrary1"
Title="MainWindow"
Width="525"
Height="350"
HeaderText="Test1234"
ShowHeader="True">
<Grid>
<TextBlock Text="test text" />
</Grid>
</uc:MyWindow>
All of this works as intended in execution, but in the designer, I don't see the header (no matter the value I set for ShowHeader), neither the HeaderText.
What should I do to make all this "blendable", and see the header in the designer ?
EDIT
I tried moving the ControlTemplate in a style
<Style TargetType="{x:Type me:MyWindow}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type me:MyWindow}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="Images/logo.gif" />
<TextBlock Grid.Column="1" Text="{TemplateBinding HeaderText}" />
</Grid>
<ContentPresenter />
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and use this
StyleProperty.OverrideMetadata(typeof(MyWindow), new FrameworkPropertyMetadata(FindResource(typeof(MyWindow))));
in Mywindow's constructor.
So now, I have the opposite, I see the header in design mode, but not in the application anymore...
EDIT2
I moved the style in Themes\Generic.xaml and added [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] in the Assemblyinfo.cs of my class library.
I also added a static constructor to my class like this:
static MyWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyWindow), new FrameworkPropertyMetadata(typeof(MyWindow)));
}
and it still doesn't work.
So now my solution structure is the following: (non-relevant parts omitted)
Solution
ClassLibrary1
Properties
AssemblyInfo.cs
Themes
Generic.xaml
MyWindow.cs
TestInheritance (the wpf app)
App.xaml
MainWindow.xaml
Edit3
Here is the link to my code: https://github.com/MerlinDuChaos/TestInheritance/
Set the default style in static constructor like this
static MyWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyWindow), new FrameworkPropertyMetadata(typeof(MyWindow)));
}
Also dont forget to set this stupid little property:
<Style TargetType="{x:Type me:MyWindow}">
<Setter Property="Background" Value="White"/>
Try it out now
EDIT:
public partial class App : Application
{
//public App()
//{
// InitializeComponent();
// FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
// {
// DefaultValue = FindResource(typeof(Window))
// });
//}
}
EDIT 2:
To force designer apply your custom window style you shall copy paste this inside app xaml.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:/ClassLibrary1;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

WPF - Custom design volume control

I have been working with WPF for some time.
I need to create the following control over Internet, but could not find appropriate.
Can anybody help how to implement this functionality. Value should be increasing or decreasing when clicked on control.
I found that I can use either Volume control or Slider, but not getting clear what I should use.
Thanks in anticipation.
I prefer to use a Progressbar for these kind of displays.
This is my implementation of a simple volume control looking pretty much like the one you show as an example:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private double _volume;
private bool mouseCaptured = false;
public double Volume
{
get { return _volume; }
set
{
_volume = value;
OnPropertyChanged("Volume");
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void MouseMove(object sender, MouseEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed && mouseCaptured)
{
var x = e.GetPosition(volumeBar).X;
var ratio = x/volumeBar.ActualWidth;
Volume = ratio*volumeBar.Maximum;
}
}
private void MouseDown(object sender, MouseButtonEventArgs e)
{
mouseCaptured = true;
var x = e.GetPosition(volumeBar).X;
var ratio = x / volumeBar.ActualWidth;
Volume = ratio * volumeBar.Maximum;
}
private void MouseUp(object sender, MouseButtonEventArgs e)
{
mouseCaptured = false;
}
#region Property Changed
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
And the XAML:
<Window x:Class="VolumeControlApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="196" Width="319">
<Window.Resources>
<Style x:Key="VolumeStyle" TargetType="{x:Type ProgressBar}">
<Setter Property="Foreground" Value="#FFB00606"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid x:Name="TemplateRoot">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"/>
<Rectangle x:Name="PART_Track"/>
<Grid x:Name="PART_Indicator" ClipToBounds="True" HorizontalAlignment="Left">
<Rectangle x:Name="Indicator" Fill="{TemplateBinding Foreground}" RadiusX="5" RadiusY="3"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Background="#FF363636">
<Border Background="Gray" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="3" Padding="2">
<Border Background="Black" CornerRadius="3">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Vol:" Foreground="White" VerticalAlignment="Center" Margin="4 0"/>
<ProgressBar x:Name="volumeBar" Height="10"
Value="{Binding Volume}"
Width="100"
MouseMove="MouseMove"
MouseDown="MouseDown"
MouseUp="MouseUp" Style="{DynamicResource VolumeStyle}" Grid.Column="1"/>
</Grid>
</Border>
</Border>
</Grid>
</Window>
You could use a slider and create a template for it.
If you need special mouse handling you'll need to subclass the slider and add logic/event handling.
The standard Slider template has a couple of repeat buttons. By simply making the left repeat button red you have a very basic implementation of the required control.
Take a look at this posts hope it helps you..
Link:
1: Sliders
2: Similar to VLC player volume control

TemplateBinding in a nested template in Silverlight 4

I've implemented a control, CommandTextBox, which I want to be a text box with a button right next to it (so it almost appears within the text box).
The button should be an image which I can bind to an icon. It's fairly straightfoward stuff...
public class CommandTextBox : TextBox
{
/// <summary>
/// The image property.
/// </summary>
public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(
"Image", typeof(ImageSource), typeof(CommandTextBox), null);
/// <summary>
/// Initializes a new instance of the <see cref = "CommandTextBox" /> class.
/// </summary>
public CommandTextBox()
{
this.DefaultStyleKey = typeof(CommandTextBox);
}
/// <summary>
/// Gets or sets the image.
/// </summary>
/// <value>
/// The image.
/// </value>
public ImageSource Image
{
get
{
return (ImageSource)this.GetValue(ImageProperty);
}
set
{
this.SetValue(ImageProperty, value);
}
}
}
I have a template as follows...
<Style TargetType="Controls:CommandTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Controls:CommandTextBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{TemplateBinding Text}"/>
<Button Grid.Column="1"
Content="Search" >
<Button.Template>
<ControlTemplate>
<Image Source="{TemplateBinding Image}" />
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But I get an error due to the template binding in the image. I sortof understand why, it's because the Template has changed now so the binding context isn't the same but I don't know how to overcome it.
Do I need to create a seperate ImageButton control so I can just do a normal template binding or is there another way?
Thanks
Ben
I have managed to get this to work by changing the style as follows:
<Style TargetType="appControls:CommandTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="appControls:CommandTextBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{TemplateBinding Text}"/>
<Button Grid.Column="1" >
<Button.Content>
<Image DataContext="{TemplateBinding Image}" Source="{Binding}" />
</Button.Content>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm not using a seperate template for the Button. My XAML with the control is:
<controls:CommandTextBox Text="Text" Image="/MyApp.Silverlight;component/Assets/Images/Amber_Triangle.png"></controls:CommandTextBox>
This appears to achieve the result you were after. The control renders on my test page as expected.

Resources