Apply Converter on Textblock inside Content Presenter - c#

I have a custom ControlTemplate for my Groupbox:
<converters:StringCaseConverter x:Key="stringCaseConverter" />
<Style TargetType="GroupBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<Border BorderBrush="#DEEBF3" BorderThickness="1,1,1,1" CornerRadius="3,3,3,3" Margin="2,2,2,2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Label Foreground="#3B3A35" FontSize="17" FontWeight="SemiBold" FontFamily="Segoe UI">
<ContentPresenter Margin="4,0,4,0" ContentSource="Header" RecognizesAccessKey="True">
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="{Binding Converter={StaticResource stringCaseConverter}, ConverterParameter='Title'}" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Label>
</StackPanel>
<ContentPresenter Grid.Row="1" Margin="14" />
</Grid>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" Opacity=".5">
<GradientStop Offset="0" Color="#AFBCC7" />
<GradientStop Offset=".1" Color="#C3D6E4" />
<GradientStop Offset=".9" Color="#C6D8E2" />
<GradientStop Offset="1" Color="#B4C3CF" />
</LinearGradientBrush>
</Border.Background>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
As you can see, there is a converter that tries to convert the header text to TitleCase using the following Converter:
[ValueConversion(typeof(string), typeof(string))]
public class StringCaseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return null;
var currentString = (string)value;
var conversion = (string)parameter;
if (conversion == "Base64")
{
byte[] txtByte = Encoding.Default.GetBytes(currentString);
string outputString = System.Convert.ToBase64String(txtByte);
return outputString;
}
if (conversion == "Upper")
return currentString.ToUpper(culture);
if (conversion == "Lower")
return currentString.ToLower(culture);
if (conversion == "Title")
{
TextInfo text = culture.TextInfo;
return text.ToTitleCase(currentString);
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The problem I am having here is that when I debug the code, the code executes perfectly and I step into the converter code, where it actually converts the header text into TitleCase. BUT... when I look at the app, the header is not reflecting what the converter returned.
Any idea why?

Related

Change predefined style inside a control in xaml

I have the following style in App.xaml:
<Style TargetType="{x:Type Button}">
<Style.Resources>
<DataTemplate x:Key="Unpressed">
<Image Stretch="Uniform" Source="Img/button1.png"/>
</DataTemplate>
<DataTemplate x:Key="Pressed">
<Image Stretch="Uniform" Source="Img/button1_press.png"/>
</DataTemplate>
</Style.Resources>
<Setter Property="ContentTemplate" Value="{StaticResource Unpressed}"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource Pressed}"/>
</Trigger>
</Style.Triggers>
</Style>
I want to change the data template from my button, something like this:
<Button x:Name="Button2">
<Style>
<Style.Resources>
<DataTemplate x:Key="Unpressed">
<Image Stretch="Uniform" Source="../Img/button2.png"/>
</DataTemplate>
<DataTemplate x:Key="Pressed">
<Image Stretch="Uniform" Source="../Img/button2_press.png"/>
</DataTemplate>
</Style.Resources>
</Style>
</Button>
So basically, all my buttons have the same style but each button have an unique image, I need to change the DataTemplate of the style individually for each button
This is my proposed solution:
For the style:
<Application.Resources>
<local:ImgToDisplayConverter x:Key="ImgToDisplayConverter"/>
<local:ImgPressedToDisplayConverter x:Key="ImgPressedToDisplayConverter"/>
<Style TargetType="Image" x:Key="PressedButtonImageStyle">
<Setter Property="Source">
<Setter.Value>
<MultiBinding Converter="{StaticResource ImgToDisplayConverter}">
<Binding Path="Tag" RelativeSource="{RelativeSource AncestorType=Button}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsPressed, RelativeSource={RelativeSource AncestorType=Button}}" Value="true">
<Setter Property="Source">
<Setter.Value>
<MultiBinding Converter="{StaticResource ImgPressedToDisplayConverter}">
<Binding Path="Tag" RelativeSource="{RelativeSource AncestorType=Button}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Application.Resources>
For the Control:
<Button Tag="button1" Width="100" Height="100" HorizontalAlignment="Left">
<ContentControl>
<Image Stretch="Uniform" Style="{StaticResource PressedButtonImageStyle}" IsHitTestVisible="False"/>
</ContentControl>
</Button>
The Converters:
class ImgToDisplayConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string image = values[0].ToString();
string resourceName = String.Format("pack://application:,,,/{0}.png", image);
return new BitmapImage(new Uri(resourceName));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
class ImgPressedToDisplayConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string image = values[0].ToString();
string resourceName = String.Format("pack://application:,,,/{0}_pressed.png", image);
return new BitmapImage(new Uri(resourceName));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can change the code depending on your needs.
I use this simple code and it works well(if you want to release the button from being pressed ,set timer).I hope this will help you..
xaml code
<Button Name="male" Height="318" Width="352" Click="male_Click" Margin="236,120,1332,642">
<Button.Background>
<ImageBrush ImageSource="pack://application:,,,/Imagesrc/logotype/USER_MALE.png" ></ImageBrush>
</Button.Background>
</Button>
pressed code
public void male_Click(object sender, RoutedEventArgs e)
{
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
img.Source = new BitmapImage(new Uri(#"pack://application:,,,/maindocket;component/Imagesrc/logotype/USER_MALE_SELECTED.png"));
male.Content = img;
}

How to use a converter for a texblock of a calendar?

I am trying to add a new column in a calendar control to add the week number. I have found a example that works perfect, the problem is very simply and it uses code behind, and I am wanted to use MVVM and a converter in another class, no inside the code behind.
Then example that I have found is this:
<Window x:Class="CalendarioNumeroSemana.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:local="clr-namespace:CalendarioNumeroSemana"
xmlns:app="clr-namespace:CalendarioNumeroSemana"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Calendar Grid.IsSharedSizeScope="True" HorizontalAlignment="Left" Margin="209,116,0,0" VerticalAlignment="Top">
<Calendar.CalendarDayButtonStyle>
<Style TargetType="{x:Type CalendarDayButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(Grid.Column),RelativeSource={RelativeSource Mode=Self}}"
Value="0">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid HorizontalAlignment="Right">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="XX"/>
<ColumnDefinition SharedSizeGroup="YY"/>
</Grid.ColumnDefinitions>
<Border BorderThickness="0,0,0,0" BorderBrush="Black" Margin="-15,0,0,0">
<TextBlock Margin="0,0,2,0" FontWeight="Bold">
<TextBlock.Text>
<Binding Path="DataContext">
<Binding.Converter>
<app:WeekNumberConverter />
</Binding.Converter>
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor"
AncestorType="{x:Type CalendarDayButton}"/>
</Binding.RelativeSource>
</Binding>
</TextBlock.Text>
</TextBlock>
</Border>
<TextBlock Text="{Binding }" Grid.Column="1" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Calendar.CalendarDayButtonStyle>
</Calendar>
</Grid>
</Window>
namespace CalendarioNumeroSemana
{
/// <summary>
/// Lógica de interacción para MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class WeekNumberConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DateTime)
{
DateTime dt = (DateTime)value;
return getNumeroSemenaIso8601(dt);
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
private int getNumeroSemenaIso8601(DateTime paramFecha)
{
System.Globalization.Calendar miCalendario = CultureInfo.InvariantCulture.Calendar;
DateTime miDtFechaBase = paramFecha;
DayOfWeek miDiaSemana = miCalendario.GetDayOfWeek(paramFecha);
if (miDiaSemana == DayOfWeek.Monday) { miDtFechaBase = miDtFechaBase.AddDays(3); }
if (miDiaSemana == DayOfWeek.Tuesday) { miDtFechaBase = miDtFechaBase.AddDays(2); }
if (miDiaSemana == DayOfWeek.Wednesday) { miDtFechaBase = miDtFechaBase.AddDays(1); }
if (miDiaSemana == DayOfWeek.Friday) { miDtFechaBase = miDtFechaBase.AddDays(-1); }
if (miDiaSemana == DayOfWeek.Saturday) { miDtFechaBase = miDtFechaBase.AddDays(-2); }
if (miDiaSemana == DayOfWeek.Sunday) { miDtFechaBase = miDtFechaBase.AddDays(-3); }
return miCalendario.GetWeekOfYear(miDtFechaBase, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
}
}
But I would like to use this in my application, that it uses MVVM and I have the converter to get the week number in another class.
My axml is this:
<Calendar Grid.IsSharedSizeScope="True" HorizontalAlignment="Left" Margin="5,5,5,5" Padding="0,0,0,0" VerticalAlignment="Top">
<Calendar.CalendarDayButtonStyle>
<Style TargetType="{x:Type CalendarDayButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(Grid.Column),RelativeSource={RelativeSource Mode=Self}}"
Value="0">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid HorizontalAlignment="Right">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="XX"/>
<ColumnDefinition SharedSizeGroup="YY"/>
</Grid.ColumnDefinitions>
<Border BorderThickness="0,0,0,0" BorderBrush="Black" Margin="-15,0,0,0">
<TextBlock Margin="0,0,2,0" FontWeight="Bold">
<TextBlock.Text>
<Binding Path="DataContext">
<Binding.Converter>
<app:WeekNumberConverter />
</Binding.Converter>
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor"
AncestorType="{x:Type CalendarDayButton}"/>
</Binding.RelativeSource>
</Binding>
</TextBlock.Text>
</TextBlock>
</Border>
<TextBlock Text="{Binding }" Grid.Column="1" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Calendar.CalendarDayButtonStyle>
</Calendar>
My main problem is that I don't know how to change the code of binding.text, and later, in TextBlock Text, it uses Binding, but I don't know what binding is this.
I have tried something like that:
<TextBlock.Text>
<Binding Converter="{StaticResource NumeroSemanaValueConverter}"/>
</TextBlock.Text>
But in the converter I don't get a date, I g et the day of the first button. I need the date.
So how could I adapt the original code to my case?
Thanks.
This has nothing to do with MVVM. It's pure control logic. The template of the control uses a converter to get the week number. A converter is just a class and a template is just a template.
So the example you have found can certainly be used in a MVVM application. It's just a built-in control with a custom template. No view model or logic that should belong to a view model is involved as far as I can see.

The Resource 'BoolToInvertedBoolConverter' could not be resolved

I am new on silverlight development. During my activity i have encountered an error which is i mentioned on the title of this post. My main purpose is popup date picker when clicking button.
<ToggleButton x:Name="TogglePopupButton" HorizontalAlignment="Right" Height="26" VerticalAlignment="Center" Grid.Column="1" Style="{StaticResource ToolIconToggleButtonStyle}" Width="26"
IsEnabled="{Binding ElementName=ToggledPopup, Path=IsOpen,Converter={StaticResource BoolToInvertedBoolConverter}}">
this is .xaml
<UserControl
<xmlns:local="clr-namespace:US.Payment.Web.Modules.PaymentMachine.Utils">
<UserControl.Resources>
<US_Payment_Web_Converters:GroupRowHeaderVisibilityConverter x:Key="GroupRowHeaderVisibilityConverter"/>
<viewModel:ImportUSPViewModel x:Name="ViewModel"/>
<local:AmountValuesConverter x:Name="AmountConverter"/>
<local:BackgroundConverter x:Key="BackgroundConverter" />
<local:BoolToInvertedBoolConverter x:Key="BoolToInvertedBoolConverter " />
<Style x:Key="CalendarDayButtonStyle1" TargetType="prim:CalendarDayButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="prim:CalendarDayButton">
<Grid Background= "{Binding Converter={StaticResource BackgroundConverter}, Path=Date}">
<ContentControl x:Name="Content" Margin="5,1,5,1" Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
This is BoolToInvertedBoolConverter.cs file
public class BoolToInvertedBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
bool boolValue = (bool)value;
return !boolValue;
}
else
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("ConvertBack() of BoolToInvertedBoolConverter is not implemented");
}
}
The problem is, you accidentally put a space character at the and of the x:Key value when declaring your resource. Remove that character and it will work.
x:Key="BoolToInvertedBoolConverter "-> has space at the end but should be
x:Key="BoolToInvertedBoolConverter" -> without space.

How to change the custom OnOff Toggle Button Width and Height at same time in WPF

I have a custom onoff toggle button style. If user change the toggle button height and width the inside ellipse(Please refer ForegroundEllipse) also change. When I set toggle button Width=50 and Height=25, the ForegroundEllipse width and height is 15. My requirement is when I change the width and height of the toggle button the ForegroundEllipse width and Height will be change. I have used converter for changing the Foreground ellipse with ration calculation. But it is not helps to me. Please anybody help me to done this, My converter is mentioned below, but that is not referred in style now. I have attached the Toggle Button design screenshot please refer,
ToggleButtonStyle
<Style x:Key="OnOffToggleButton" TargetType="{x:Type ToggleButton}">
<Style.Resources>
<Color x:Key="Color.Additional.LightGrey">#FFFFFF</Color>
<Color x:Key="Color.Additional.MediumGrey">#61656B</Color>
<Color x:Key="Color.MedtronicBranding.MedtronicBlue">#FFFFFF</Color>
<Color x:Key="Color.MedtronicBranding.CobaltBlue">#14BBA0</Color>
<Style x:Key="ToggleButtonContentTextbox" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
<SolidColorBrush x:Key="ToggleButtonFalseBackground" Color="{StaticResource Color.Additional.LightGrey}" />
<SolidColorBrush x:Key="ToggleButtonTrueBackground" Color="{Binding ParentTemplate.Background}"/>
<SolidColorBrush x:Key="ToggleButtonFalseForeground" Color="{StaticResource Color.Additional.MediumGrey}" />
<SolidColorBrush x:Key="ToggleButtonTrueForeground" Color="{StaticResource Color.MedtronicBranding.MedtronicBlue}" />
<Style x:Key="OnContentControl" TargetType="ContentControl">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock
FontSize="8"
Foreground="White"
Style="{StaticResource ToggleButtonContentTextbox}"
Text="ON" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
<Style x:Key="OffContentControl" TargetType="ContentControl">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock
FontSize="8"
Foreground="White"
Style="{StaticResource ToggleButtonContentTextbox}"
Text="OFF" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid x:Name="MainRow">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=TopRow, Path=ActualHeight}" />
<ColumnDefinition />
<ColumnDefinition Width="{Binding ElementName=TopRow, Path=ActualHeight}" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="TopRow" />
<RowDefinition />
</Grid.RowDefinitions>
<Ellipse
x:Name="BackgroundEllipse1"
Grid.RowSpan="2"
Grid.Column="0"
Grid.ColumnSpan="3"
Width="{Binding ElementName=MainRow, Path=ActualHeight}"
Height="{Binding ElementName=MainRow, Path=ActualHeight}"
HorizontalAlignment="Left"
Fill="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Control}, AncestorLevel=1}}" />
<Ellipse
x:Name="BackgroundEllipse2"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Grid.ColumnSpan="3"
Width="{Binding ElementName=MainRow, Path=ActualHeight}"
Height="{Binding ElementName=MainRow, Path=ActualHeight}"
HorizontalAlignment="Right"
Fill="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Control}, AncestorLevel=1}}"/>
<Border
x:Name="BackgroundBorder"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Control}, AncestorLevel=1}}" />
</Grid>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="AnimationWidth" />
<ColumnDefinition Width="{Binding ElementName=MainRow, Path=ActualHeight}" />
</Grid.ColumnDefinitions>
<Border x:Name="AnimationSizeBorder" Grid.Column="0" />
<ContentControl Grid.Column="0" Style="{StaticResource OnContentControl}" />
</Grid>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=MainRow, Path=ActualHeight}" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="1" Style="{StaticResource OffContentControl}" />
</Grid>
<Grid Background="Transparent">
<StackPanel
Margin="5,0,0,0"
HorizontalAlignment="Stretch"
Orientation="Horizontal">
<Border Width="{Binding ElementName=AnimationSizeBorder, Path=ActualWidth}" />
<Ellipse
x:Name="ForegroundEllipse"
HorizontalAlignment="Right"
Width="15"
Height="15"
Fill="{StaticResource ToggleButtonTrueForeground}"/>
</StackPanel>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="BackgroundBorder" Property="Background" Value="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Control}, AncestorLevel=1}}" />
<Setter TargetName="ForegroundEllipse" Property="Fill" Value="White" />
<Setter TargetName="AnimationSizeBorder" Property="Width" Value="0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MainWindow.xaml
<Grid>
<ToggleButton
Width="50"
Height="25"
Margin="0,10,0,0"
IsChecked="False"
Background="BlueViolet"
Style="{StaticResource OnOffToggleButton}"
HorizontalAlignment="Center"/>
</Grid>
Converters
public class SumHeightConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var firstValue = (object)values[0];
var secondValue = (object)values[1];
var value = ((double)15 * (double)firstValue) / (double)25;
double _Sum = 0;
if (firstValue != null && secondValue != null)
{
_Sum = value;
}
return _Sum;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class SumWidthConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double _Sum = 0;
var firstValue = (object)values[0];
var secondValue = (object)values[1];
var value = ((double)15 * (double)firstValue) / (double)50;
if (firstValue != null && secondValue != null)
{
_Sum = value;
}
return _Sum;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[][2

Attach Dependency Property to User Control

How to register DependencyProperty on Rectangle fill, so i can change the color
dynamically?
<UserControl.Resources>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Stroke="Black">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF48B6E4" Offset="0.013"/>
<GradientStop Color="#FF091D8D" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<Button Style="{DynamicResource ButtonStyle1}"/>
<TextBlock
x:Name="NodeName"
x:FieldModifier="public"
Text="Property"
Margin="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap"
TextAlignment="Center"
FontFamily="Segoe Print"
FontWeight="Bold"
Foreground="White"
FontSize="40"/>
</Grid>
Why don't you bind Fill to the Background property of the Button:
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Stroke="Black" Fill="{TemplateBinding Background}" />
...
</Grid>
...
</ControlTemplate>
and then set Background like this:
<Button Style="{DynamicResource ButtonStyle1}">
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF48B6E4" Offset="0.013"/>
<GradientStop Color="#FF091D8D" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
If you have your own dependency property called MyProperty registered in your UserControl, you can bind it this way:
...
<Rectangle Stroke="Black" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Parent.Parent.MyProperty}" />
...
No other changes are needed.
This binds the Fill property to parent of parent of the control to which the style is assigned, in your case the UserControl itself.
Using this method you can not only bind it to properties of a UserControl, but also to other controls' properties.
I would create a dependency property on your YourUserControl view, something like this (I removed some of your markup for brevity):
<UserControl.Resources>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Stroke="Black" Fill="{TemplateBinding Background}">
</Rectangle>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Grid x:Name="LayoutRoot">
<Button Style="{DynamicResource ButtonStyle1}" Background="{Binding DynamicColor}"/>
</Grid>
Then in YourUserControl.xaml.cs you could create your dependency property:
private My_ViewModel _viewModel
{
get { return this.DataContext as My_ViewModel; }
}
public LinearGradientBrush DynamicColor
{
get { return (string)GetValue(DynamicColorProperty); }
set { SetValue(DynamicColorProperty, value); }
}
public static readonly DependencyProperty DynamicColorProperty =
DependencyProperty.Register("DynamicColor", typeof(LinearGradientBrush), typeof(YourUserControl),
new PropertyMetadata(new PropertyChangedCallback(OnDynamicColorPropertyChanged)));
private static void OnDynamicColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((YourUserControl)d).OnTrackerInstanceChanged(e);
}
protected virtual void OnDynamicColorPropertyChanged(DependencyPropertyChangedEventArgs e)
{
this._viewModel.DynamicColor = e.NewValue;
}
public class My_ViewModel : INotifyPropertyChanged
{
public LinearGradientBrush DynamicColor
{
get { return dynamicColor; }
set
{
if(dynamicColor != value)
{
dynamicColor = value;
OnPropertyChanged("DynamicColor");
}
}
}
private LinearGradientBrush dynamicColor;
}
This approach gives you complete control over the DynamicColor property's value as well as allows you to be able to unit test the behavior effectively.

Categories