Sure Im missing something simple but I have overridden a checkbox as a user control so I can use different images as its bullet decorators. Seems to work ok but doesnt respond to any click or checked events. I need it to display the bound popup upon the click evnt but not change the bullet decorator images.
Also my binding seems to be broken as when the click even fires (once it works) it should present a popup with the bound data. WarningList is my data to bind and when debugging it shows its populated correctly, just not bound correctly I believe
<UserControl x:Class="Dev.App.Views.Controls.StatusResultCheckBox"
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:converters="clr-namespace:Dev.App.Views.Converters"
x:Name="Root"
d:DesignHeight="50"
d:DesignWidth="50"
mc:Ignorable="d">
<UserControl.Resources>
<converters:WarningListFilterByOperationTypeConverter x:Key="WarningListFilterByOperationTypeConverter" />
<DataTemplate x:Key="StatusResultNone">
<Viewbox Width="20" Height="20">
<Grid/>
</Viewbox>
</DataTemplate>
<DataTemplate x:Key="StatusResultWarning">
<BulletDecorator Background="Transparent">
<BulletDecorator.Bullet>
<Viewbox Width="20" Height="20">
<Grid>
<Path Data="F1M874.094,289.369L854.3,254.63C854.028,254.151 853.515,253.856 852.958,253.856 852.403,253.856 851.89,254.151 851.617,254.63L831.824,289.369C831.555,289.84 831.559,290.416 831.835,290.883 832.111,291.348 832.618,291.634 833.165,291.634L872.752,291.634C873.299,291.634 873.805,291.348 874.081,290.883 874.357,290.416 874.361,289.84 874.094,289.369z"
Stretch="Uniform" Fill="#FFFCCE00" Width="20" Height="20" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5" StrokeThickness="0.5">
</Path>
<Path Data="M855.653,287.189L850.264,287.189 850.264,282.745 855.653,282.745 855.653,287.189z M855.653,279.41L850.264,279.41 850.264,266.077 855.653,266.077 855.653,279.41z"
Stretch="Uniform" Fill="Black" Width="3" Height="10" Margin="0.5,3,0,0" RenderTransformOrigin="0.5,0.5" StrokeThickness="0.5">
</Path>
</Grid>
</Viewbox>
</BulletDecorator.Bullet>
<Popup Name="WarningMessagePopup"
Width="{Binding ElementName=ListBox, Path=ActualWidth}"
Height="200"
HorizontalAlignment="Center"
HorizontalOffset="50"
PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
IsOpen="{Binding Path=IsChecked}"
StaysOpen="False"
VerticalOffset="10">
<TextBox VerticalScrollBarVisibility="Auto">
<TextBox.Text>
<MultiBinding Converter="{StaticResource WarningListFilterByOperationTypeConverter}" Mode="OneWay">
<Binding Path="OperationType" />
<Binding Path="DataContext.WarningList" RelativeSource="{RelativeSource AncestorType=ListBox}" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</Popup>
</BulletDecorator>
</DataTemplate>
<ControlTemplate x:Key="CheckBoxTemplate" TargetType="ContentControl">
<ContentControl Name="Content" />
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding StatusResultCheckMode, ElementName=Root}" Value="None">
<Setter TargetName="Content" Property="ContentTemplate" Value="{StaticResource StatusResultNone}" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusResultCheckMode, ElementName=Root}" Value="Warning">
<Setter TargetName="Content" Property="ContentTemplate" Value="{StaticResource StatusResultWarning}" />
<Setter Property="Cursor" Value="Hand" />
</DataTrigger>
<DataTrigger Binding="{Binding HasStatus, ElementName=Root}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="StatusResultVisibilityStyle" TargetType="CheckBox">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<BulletDecorator Background="Transparent">
<BulletDecorator.Bullet>
<Viewbox Width="20" Height="20">
<Grid />
</Viewbox>
</BulletDecorator.Bullet>
</BulletDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsInStatusNone.Value}" Value="False" />
<Condition Binding="{Binding IsInStatusWarning.Value}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Visible" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox HorizontalAlignment="Center"
VerticalAlignment="Center"
IsChecked="True"
Style="{StaticResource StatusResultVisibilityStyle}"/>
<ContentControl Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="20" Height="20"
Template="{StaticResource CheckBoxTemplate}" />
</Grid>
</UserControl>
Called from my main page as follows. (nested inside a Listbox)
<controls:StatusResultCheckBox Grid.Column="3"
IsInStatusWarning="{Binding Path=IsInStatusWarning.Value}"
IsInStatusNone="{Binding Path=IsInStatusNone.Value}"
HasStatus="{Binding Path=HasStatus.Value}"
IsRunning="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext.IsRunning.Value}"/>
The code behind the user control...
using System.Windows;
using System.Windows.Controls;
namespace Dev.App.Views.Controls
{
/// <summary>
/// Interaction logic for StatusResultCheckBox.xaml
/// </summary>
public partial class StatusResultCheckBox : UserControl
{
public static readonly DependencyProperty StatusResultCheckModeProperty =
DependencyProperty.Register("StatusResultCheckMode", typeof(StatusResultCheckMode), typeof(StatusResultCheckBox), new PropertyMetadata(StatusResultCheckMode.None));
public static readonly DependencyProperty IsRunningProperty =
DependencyProperty.Register("IsRunning", typeof(bool), typeof(StatusResultCheckBox), new PropertyMetadata(false, IsRunningPropertyChanged));
public static readonly DependencyProperty HasStatusProperty =
DependencyProperty.Register("HasStatus", typeof(bool), typeof(StatusResultCheckBox), new PropertyMetadata(false, IsRunningPropertyChanged));
public static readonly DependencyProperty IsInStatusWarningProperty =
DependencyProperty.Register("IsInStatusWarning", typeof(bool), typeof(StatusResultCheckBox), new PropertyMetadata(false, IsRunningPropertyChanged));
public static readonly DependencyProperty IsInStatusNoneProperty =
DependencyProperty.Register("IsInStatusNone", typeof(bool), typeof(StatusResultCheckBox), new PropertyMetadata(false, IsRunningPropertyChanged));
private static void IsRunningPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var statusResultCheckBox = d as StatusResultCheckBox;
if (statusResultCheckBox != null)
{
if (statusResultCheckBox.IsRunning)
{
if (statusResultCheckBox.IsInStatusWarning)
{
statusResultCheckBox.StatusResultCheckMode = StatusResultCheckMode.Warning;
statusResultCheckBox.HasStatus = true;
}
else
{
statusResultCheckBox.StatusResultCheckMode = StatusResultCheckMode.None;
statusResultCheckBox.HasStatus = false;
}
}
}
}
public StatusResultCheckBox()
{
InitializeComponent();
}
public StatusResultCheckMode StatusResultCheckMode
{
get { return (StatusResultCheckMode)GetValue(StatusResultCheckModeProperty); }
set { SetValue(StatusResultCheckModeProperty, value); }
}
public bool IsRunning
{
get { return (bool)GetValue(IsRunningProperty); }
set { SetValue(IsRunningProperty, value); }
}
public bool HasStatus
{
get { return (bool)GetValue(HasStatusProperty); }
set { SetValue(HasStatusProperty, value); }
}
public bool IsInStatusWarning
{
get { return (bool)GetValue(IsInStatusWarningProperty); }
set { SetValue(IsInStatusWarningProperty, value); }
}
public bool IsInStatusNone
{
get { return (bool)GetValue(IsInStatusNoneProperty); }
set { SetValue(IsInStatusNoneProperty, value); }
}
}
public enum StatusResultCheckMode
{
None,
Warning
}
}
If you want to do something like this, it probably will be easier if you just apply a style to a existing checkbox.
You can get the default style from here and change what you need.
Ended up refactoring all this code and simplifying. Basically styled a togglebutton.
<ToggleButton Grid.Column="3" Style="{StaticResource WarningStyle}"/>
And in the resource file...
<Style x:Key="WarningStyle" TargetType="ToggleButton">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Path Data="F1M874.094,289.369L854.3,254.63C854.028,254.151 853.515,253.856 852.958,253.856 852.403,253.856 851.89,254.151 851.617,254.63L831.824,289.369C831.555,289.84 831.559,290.416 831.835,290.883 832.111,291.348 832.618,291.634 833.165,291.634L872.752,291.634C873.299,291.634 873.805,291.348 874.081,290.883 874.357,290.416 874.361,289.84 874.094,289.369z"
Stretch="Uniform" Fill="#FFFCCE00" Width="20" Height="20" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5" StrokeThickness="0.5">
</Path>
<Path Data="M855.653,287.189L850.264,287.189 850.264,282.745 855.653,282.745 855.653,287.189z M855.653,279.41L850.264,279.41 850.264,266.077 855.653,266.077 855.653,279.41z"
Stretch="Uniform" Fill="Black" Width="3" Height="10" Margin="0.5,3,0,0" RenderTransformOrigin="0.5,0.5" StrokeThickness="0.5">
</Path>
<Popup Name="WarningMessagePopup"
Width="425"
Height="150"
HorizontalAlignment="Center"
HorizontalOffset="22"
PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
IsOpen="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked}"
StaysOpen="False"
VerticalOffset="7">
<ListBox ItemsSource="{Binding Path=WarningList}">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<Trigger Property="IsVisible" Value="True">
<Setter Property="Background" Value="#F8FCFF"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource WarningListFilterByOperationTypeConverter}" Mode="OneWay">
<Binding Path="Count" />
<Binding Path="Message" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsInStatusWarning.Value}" Value="True" >
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
Related
I have a custom RadioButton style with an Image and 2 TextBlocks.
<Style x:Key="ToggleButton_Chose" TargetType="{x:Type ToggleButton}" >
<Setter Property="Background" Value="#32353B" />
<Setter Property="Margin" Value="10,5"/>
<Setter Property="Height" Value="45" />
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Padding" Value="1" />
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel>
<Border BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0">
<ContentPresenter HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<Image Source="{TemplateBinding Button.Tag}" HorizontalAlignment="Left" Stretch="Uniform" Width="45" IsEnabled="True" />
<StackPanel Margin="2">
<TextBlock Foreground="#DCDDDE" FontSize="18" FontFamily="Arial">Strona</TextBlock>
<TextBlock Foreground="#52555C" FontSize="12" FontFamily="Arial"> Login</TextBlock>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="#282B2E"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#FF282B2E" Opacity="0.5"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
When I create a new button at runtime, setting the Style and I want to change the Image and the text for every single RadioButton. Right now I am thinking about using a Tag for that.
RadioButton radioButton = new RadioButton();
radioButton.GroupName = "Side";
radioButton.Style = (Style)Resources["ToggleButton_Chose"];
radioButton.Tag = new BitmapImage(new Uri("https://www.google.com/favicon.ico"));
Is there any other method to set this?
I will have around 100 of the RadioButtons and any of them should get different images and texts.
Custom Control
If you want to create a ToggleButton that requires additional (bindable) properties, you could create a custom control with dependency properties for the image and texts based on the ToggleButton type. Create a new type AdvancedToggleButton that derives from ToggleButton.
public class AdvancedToggleButton : ToggleButton
{
static AdvancedToggleButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AdvancedToggleButton), new FrameworkPropertyMetadata(typeof(AdvancedToggleButton)));
}
public ImageSource ImageSource
{
get => (ImageSource) GetValue(ImageSourceProperty);
set => SetValue(ImageSourceProperty, value);
}
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
nameof(ImageSource), typeof(ImageSource), typeof(AdvancedToggleButton));
public string FirstText
{
get => (string) GetValue(FirstTextProperty);
set => SetValue(FirstTextProperty, value);
}
public static readonly DependencyProperty FirstTextProperty = DependencyProperty.Register(
nameof(FirstText), typeof(string), typeof(AdvancedToggleButton));
public string SecondText
{
get => (string) GetValue(SecondTextProperty);
set => SetValue(SecondTextProperty, value);
}
public static readonly DependencyProperty SecondTextProperty = DependencyProperty.Register(
nameof(SecondText), typeof(string), typeof(AdvancedToggleButton));
}
Then you can create a default implicit style (by omitting the x:Key) in your application resources or another resource dictionary in scope, so the style is applied automatically.
<Style TargetType="{x:Type local:AdvancedToggleButton}">
<Setter Property="Background"
Value="#32353B" />
<Setter Property="Margin"
Value="10,5" />
<Setter Property="Height"
Value="45" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Padding"
Value="1" />
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AdvancedToggleButton}">
<StackPanel>
<Border BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left"
Margin="0">
<ContentPresenter HorizontalAlignment="Left"
VerticalAlignment="Center" />
<Image Source="{TemplateBinding ImageSource}"
HorizontalAlignment="Left"
Stretch="Uniform"
Width="45"
IsEnabled="True" />
<StackPanel Margin="2">
<TextBlock Foreground="#DCDDDE"
FontSize="18"
FontFamily="Arial"
Text="{TemplateBinding FirstText}"/>
<TextBlock Foreground="#52555C"
FontSize="12"
FontFamily="Arial"
Text="{TemplateBinding SecondText}"/>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="Background"
Value="#282B2E" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#FF282B2E"
Opacity="0.5" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Note, that I removed the duplicate setter for HorizontalAlignment. The Image binds its Source to the ImageSource property and the TextBlocks bind to FirstText and SecondText respectively. You can either define the AdvancedToggleButton in XAML or code.
<local:AdvancedToggleButton ImageSource="\Resources/Check.jpg"
FirstText="Strona"
SecondText="Login"/>
RadioButton radioButton = new RadioButton();
radioButton.GroupName = "Side";
radioButton.ImageSource = new BitmapImage(new Uri("https://www.google.com/favicon.ico"));
radioButton.FirstText = "Strona";
radioButton.SecondText = "Login"
Useful resources on custom controls:
Control authoring overview
Dependency properties overview
Attached Properties
An alternative without creating a custom control is to create a set of attached properties.
public static class ToggleButtonProperties
{
public static ImageSource GetImageSource(DependencyObject dependencyObject)
{
return (ImageSource) dependencyObject.GetValue(ImageSourceProperty);
}
public static void SetImageSource(DependencyObject dependencyObject, ImageSource value)
{
dependencyObject.SetValue(ImageSourceProperty, value);
}
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.RegisterAttached(
"ImageSource", typeof(ImageSource), typeof(ToggleButtonProperties));
public static string GetFirstText(DependencyObject dependencyObject)
{
return (string) dependencyObject.GetValue(FirstTextProperty);
}
public static void SetFirstText(DependencyObject dependencyObject, string value)
{
dependencyObject.SetValue(FirstTextProperty, value);
}
public static readonly DependencyProperty FirstTextProperty = DependencyProperty.RegisterAttached(
"FirstText", typeof(string), typeof(ToggleButtonProperties));
public static string GetSecondText(DependencyObject dependencyObject)
{
return (string) dependencyObject.GetValue(SecondTextProperty);
}
public static void SetSecondText(DependencyObject dependencyObject, string value)
{
dependencyObject.SetValue(SecondTextProperty, value);
}
public static readonly DependencyProperty SecondTextProperty = DependencyProperty.RegisterAttached(
"SecondText", typeof(string), typeof(ToggleButtonProperties));
}
These properties can be bound in the control template using parentheses, which is the binding syntax for attached properties and RelativeSource to the parent ToggleButton.
<Style x:Key="ToggleButton_Chose" TargetType="{x:Type ToggleButton}">
<Setter Property="Background"
Value="#32353B" />
<Setter Property="Margin"
Value="10,5" />
<Setter Property="Height"
Value="45" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Padding"
Value="1" />
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel>
<Border BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left"
Margin="0">
<ContentPresenter HorizontalAlignment="Left"
VerticalAlignment="Center" />
<Image Source="{Binding (local:ToggleButtonProperties.ImageSource), RelativeSource={RelativeSource TemplatedParent}}"
HorizontalAlignment="Left"
Stretch="Uniform"
Width="45"
IsEnabled="True" />
<StackPanel Margin="2">
<TextBlock Foreground="#DCDDDE"
FontSize="18"
FontFamily="Arial"
Text="{Binding (local:ToggleButtonProperties.FirstText), RelativeSource={RelativeSource TemplatedParent}}"/>
<TextBlock Foreground="#52555C"
FontSize="12"
FontFamily="Arial"
Text="{Binding (local:ToggleButtonProperties.SecondText), RelativeSource={RelativeSource TemplatedParent}}"/>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="Background"
Value="#282B2E" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#FF282B2E"
Opacity="0.5" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Assigning or binding the attached properties is done via the static class.
<ToggleButton Style="{StaticResource ToggleButton_Chose}"
local:ToggleButtonProperties.ImageSource="\Resources/Check.jpg"
local:ToggleButtonProperties.FirstText="Strona"
local:ToggleButtonProperties.SecondText="Login"/>
RadioButton radioButton = new RadioButton();
radioButton.GroupName = "Side";
ToggleButtonProperties.SetImageSource(radioButton, new BitmapImage(new Uri("https://www.google.com/favicon.ico")));
ToggleButtonProperties.SetFirstText(radioButton, "Strona");
ToggleButtonProperties.SetSecondText(radioButton, "Login");
Useful resources on attached properties:
Attached Properties Overview
But is ther any other method to sett this? I will have around 100 of the RadioButtons and any of there should get other image and text.
Create a simple data type:
public class ButtonContent
{
public string Strona { get; set; }
public string Login { get; set; }
public object ImageSource { get; set; }
}
This type will be used to pass the button data into the context.
Therefore, we will slightly change the style:
<Style x:Key="ToggleButton_Chose" TargetType="{x:Type ToggleButton}" >
<Setter Property="Background" Value="#32353B" />
<Setter Property="Margin" Value="10,5"/>
<Setter Property="Height" Value="45" />
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Padding" Value="1" />
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel>
<Border BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0">
<ContentPresenter HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<Image Source="{Binding ImageSource}"
HorizontalAlignment="Left" Stretch="Uniform" Width="45" IsEnabled="True" />
<StackPanel Margin="2">
<TextBlock Foreground="#DCDDDE" FontSize="18" FontFamily="Arial"
Text="{Binding Strona}"/>
<TextBlock Foreground="#52555C" FontSize="12" FontFamily="Arial"
Text="{Binding Login}"/>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="#282B2E"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#FF282B2E" Opacity="0.5"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
For a set of buttons use ItemsControl:
<DataTemplate x:Key="itemTemplate" DataType="{x:Type local:ButtonContent}">
<ToggleButton Style="{DynamicResource ToggleButton_Chose}"/>
</DataTemplate>
<ItemsControl x:Name="itemsControl"
ItemTemplate="{DynamicResource itemTemplate}">
</ItemsControl>
Create an observable collection with data and pass it to the ItemsControl source:
public partial class MainWindow : Window
{
private readonly ObservableCollection<ButtonContent> ButtonContents
= new ObservableCollection<ButtonContent>();
public MainWindow()
{
InitializeComponent();
itemsControl.ItemsSource = ButtonContents;
ButtonContents.Add(new ButtonContent() { Strona = "Strona1", Login = "Login1", ImageSource = "Image/block.png" });
ButtonContents.Add(new ButtonContent() { Strona = "Strona2", Login = "Login2", ImageSource = "Image/block.png" });
ButtonContents.Add(new ButtonContent() { Strona = "Strona3", Login = "Login3", ImageSource = "Image/block.png" });
ButtonContents.Add(new ButtonContent() { Strona = "Strona4", Login = "Login4", ImageSource = "Image/block.png" });
}
}
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
Having trouble binding to the data in my code behind for my custom control. Obviously I have got to use the Generic.xaml to style my control, and I want to bind to the data in my control UserProfile.cs.
This is the code behind:
using System;
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
public class UserProfile : Control
{
static UserProfile()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UserProfile),
new FrameworkPropertyMetadata(typeof(UserProfile)));
}
private Double _ProfilePhotoSize = 50;
private Double ProfilePhotoSize
{
get { return _ProfilePhotoSize; }
set
{
if (_ProfilePhotoSize != value)
_ProfilePhotoSize = value;
}
}
}
}
And here is the XAML with the binding, removed the last part as it isn't needed:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Controls">
<Style TargetType="{x:Type local:NumericUpDown}">
<Style.Resources>
<SolidColorBrush x:Key="colour1" Color="#434953" />
<SolidColorBrush x:Key="colour2" Color="#22252b" />
<SolidColorBrush x:Key="colour3" Color="#606876" />
</Style.Resources>
<Setter Property="Width" Value="85" />
<Setter Property="Margin" Value="5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:NumericUpDown}">
<Border Focusable="{TemplateBinding Focusable}"
Width="{TemplateBinding Width}"
x:Name="Border">
<Grid Focusable="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button x:Name="PART_DecreaseButton"
Grid.Column="0">
<Button.Content>
<Path Data="M0,0 L1,0 0.5,1Z"
Fill="White"
Width="8"
Height="6"
Stretch="Fill"/>
</Button.Content>
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Name="Border"
Background="{DynamicResource colour1}"
Width="25"
Height="25"
CornerRadius="5 0 0 5">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource colour3}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
<TextBox x:Name="PART_TextBox"
Grid.Column="1"
Foreground="White"
Background="{DynamicResource colour2}"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
HorizontalAlignment="Stretch"
BorderThickness="0"
Focusable="False" Text="0" />
<Button x:Name="PART_IncreaseButton"
Grid.Column="2">
<Button.Content>
<Path Data="M0,1 L1,1 0.5,0Z"
Width="8"
Height="6"
Fill="White"
Stretch="Fill" />
</Button.Content>
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Name="Border"
Background="{DynamicResource colour1}"
Width="25"
Height="25"
CornerRadius="0 5 5 0">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource colour3}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:UserProfile}">
<Setter Property="DataContext" Value="{x:Type local:UserProfile}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:UserProfile}">
<Grid x:Name="circleGrid" Width="{Binding Path=ProfilePhotoSize, RelativeSource={RelativeSource AncestorType={x:Type local:UserProfile}}}">
...
This is the binding error i'm getting:
BindingExpression path error: 'ProfilePhotoSize' property not found on
'object' ''UserProfile' (Name='')'.
BindingExpression:Path=ProfilePhotoSize; DataItem='UserProfile'
(Name=''); target element is 'Grid' (Name='circleGrid'); target
property is 'Width' (type 'Double')
Edit:
Just moved some code around and getting issue with the code now, I want to the border size to adjust based on the size the user makes the control, so I have made a new class and property which gets the ProfilePhotoSize and then will divide it by a number.
Code Behind
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
public class UserProfile : Control
{
static UserProfile()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UserProfile),
new FrameworkPropertyMetadata(typeof(UserProfile)));
}
}
public class UserProfileData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
private Double _ProfilePhotoSize = 50;
public Double ProfilePhotoSize
{
get { return _ProfilePhotoSize; }
set
{
if (_ProfilePhotoSize != value)
_ProfilePhotoSize = value;
OnPropertyChanged("ProfilePhotoSize");
}
}
private Double _ProfileBorderThickness = 3;
public Double ProfileBorderThickness
{
get { return _ProfileBorderThickness; }
set
{
double x = ProfilePhotoSize / 3;
if (_ProfileBorderThickness != x)
_ProfileBorderThickness = x;
OnPropertyChanged("ProfileBorderThickness");
}
}
}
}
This is the XAML, binding no longer works :S
XAML
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Controls">
<Style TargetType="{x:Type local:UserProfile}">
<Setter Property="DataContext" Value="{x:Type local:UserProfile}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:UserProfile}">
<Grid x:Name="circleGrid" Width="{Binding ProfilePhotoSize, RelativeSource={RelativeSource AncestorType={x:Type local:UserProfileData}}}">
<Grid.RowDefinitions>
change it to a public property.
private Double _ProfilePhotoSize = 50;
public Double ProfilePhotoSize
{
get { return _ProfilePhotoSize; }
set
{
if (_ProfilePhotoSize != value)
_ProfilePhotoSize = value;
}
}
<Style TargetType="controls:ModernVerticalMenu" >
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ModernVerticalMenu">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{TemplateBinding ListWidth}"/>
<ColumnDefinition Width="{TemplateBinding ListWidth}"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Background="{DynamicResource background}" Height="{TemplateBinding Height}" BorderThickness="1" BorderBrush="{DynamicResource bordaSuperior}">
<!-- link list -->
<ListBox x:Name="LinkList" ItemsSource="{TemplateBinding Links}"
ScrollViewer.HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="50" Background="Transparent" Width="500">
<Border Padding="10">
<Path x:Name="icon" Data="{Binding IconData}" Stretch="Fill" Fill="{DynamicResource Accent}" Width="20" Height="20" HorizontalAlignment="Left" VerticalAlignment="Center" />
</Border>
<TextBlock x:Name="texto" ToolTip="{Binding Tooltip}" Text="{Binding DisplayName}" Margin="45,2,2,2" FontSize="{DynamicResource MediumFontSize}" TextTrimming="CharacterEllipsis" VerticalAlignment="Center" HorizontalAlignment="Left" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IconData}" Value="{x:Null}">
<Setter Property="Margin" TargetName="texto">
<Setter.Value>
<Thickness Bottom="2" Top="2" Left="10" Right="2"/>
</Setter.Value>
</Setter>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="icon">
<Setter.Value>
<SolidColorBrush Color="#f2f2f2" />
</Setter.Value>
</Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I created a custom control and I am creating a template for a vertical menu, I wanna that in the event of MouseOver of the ListBox, I could set the value of proprierty of the controls:ModernVerticalMenu,
any idea?
When I write parent, is the ModerVerticalMenu and child is the ListBox from the ControlTemplate.
The main idea is to somehow get access to parent object and change its property. In order to do this I create one attached property retrieving access to parent by TemplatedParent markup, second attached property stores value which is supposed to be applied in parent's property. This sample is not precise your problem but on the right track, I believe.
I want to change button Content, which is initially Empty. First textblock reflects change in Button's Content to find out whether any occured.
<StackPanel>
<TextBlock Text="{Binding ElementName=but, Path=Content}"/>
<Button Name="but" Content="" Background="CadetBlue" BorderBrush="CadetBlue" BorderThickness="2">
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBox Margin="50" Text="xD" local:MyClass.Parent="{Binding RelativeSource={RelativeSource AncestorType=Button}}">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="local:MyClass.Content" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True">
<Setter Property="Foreground" Value="CadetBlue"/>
<Setter Property="local:MyClass.Content" Value="tekst"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
Class with attached properties looks as follows
public static class MyClass
{
public static void SetParent(DependencyObject obj, Button val)
{
obj.SetValue(ParentProperty, val);
}
public static Button GetParent(DependencyObject obj)
{
return (Button)obj.GetValue(ParentProperty);
}
public static readonly DependencyProperty ParentProperty = DependencyProperty.RegisterAttached("Parent", typeof(Button), typeof(MyClass), new PropertyMetadata(null, new PropertyChangedCallback(
(x, y) =>
{
Debug.WriteLine(GetParent(x));
})));
public static void SetContent(DependencyObject obj, string val)
{
obj.SetValue(ContentProperty, val);
}
public static string GetContent(DependencyObject obj)
{
return (string)obj.GetValue(ContentProperty);
}
public static readonly DependencyProperty ContentProperty = DependencyProperty.RegisterAttached("Content", typeof(string), typeof(MyClass), new PropertyMetadata(null, new PropertyChangedCallback(
(x, y) =>
{
if (GetContent(x) != String.Empty)
((Button)GetParent(x)).Content = GetContent(x);
})));
}
When mouse is over textbox then parent's property content changes to value of attached property set in setter
<Setter Property="local:MyClass.Content" Value="tekst"/>
I have simple custom control that shows a message to user (something like browser's Info bar).
I have added a Boolean Dependency Property that indicate an error message. If flag is set the background color of control should be red otherwise yellow.
Here is style for the control(in Themes\Generic.xaml):
<Style TargetType="{x:Type local:InfoBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:InfoBar}">
<ControlTemplate.Triggers>
<Trigger Property="IsError" Value="True" >
<Setter Property="Background" Value="LightPink" />
</Trigger>
<Trigger Property="IsError" Value="False" >
<Setter Property="Background" Value="LightYellow" />
</Trigger>
</ControlTemplate.Triggers>
<Grid Margin="4,0,4,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{TemplateBinding Message}" Padding="5" FontWeight="Normal" TextWrapping="Wrap" Grid.Column="0"/>
<Button x:Name="PART_CloseButton" Grid.Column="1" VerticalAlignment="Top" >
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="Transparent">
<Image Height="16" Width="16" Source="/QOffice.Common.Controls;component/Images/icons/Close.png" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is The control itself:
[TemplatePart(Name = PART_CloseButton, Type = typeof(ButtonBase))]
public class InfoBar : Control
{
private const string PART_CloseButton = "PART_CloseButton";
static InfoBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(InfoBar), new FrameworkPropertyMetadata(typeof(InfoBar)));
}
#region CloseButton
private ButtonBase _closeButton;
/// <summary>
/// Gets or sets the CloseButton template part.
/// </summary>
private ButtonBase CloseButton
{
get
{
return _closeButton;
}
set
{
if (_closeButton != null)
{
_closeButton.Click -= OnButtonClick;
}
_closeButton = value;
if (_closeButton != null)
{
_closeButton.Click += OnButtonClick;
}
}
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
this.Visibility = System.Windows.Visibility.Collapsed;
}
#endregion
public override void OnApplyTemplate()
{
CloseButton = GetTemplateChild(PART_CloseButton) as ButtonBase;
}
#region DependencyProperty Message of InfoBar
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(InfoBar),
new UIPropertyMetadata());
#endregion
#region DependencyProperty IsError of InfoBar
public bool IsError
{
get { return (bool)GetValue(IsErrorProperty); }
set { SetValue(IsErrorProperty, value); }
}
public static readonly DependencyProperty IsErrorProperty =
DependencyProperty.Register("IsError", typeof(bool), typeof(InfoBar),
new UIPropertyMetadata());
#endregion
}
As you can see I have defined a property IsError and a trigger to set the background of the control.
But the background is always transparent. Other than that the control if functional.
What is wrong?
It seems that your Custom Control is not setting Background Color properly even if I add Background color manually. I am not sure why this is, hopefully someone can elaborate. I did fix your issue though by changing the color of the Grid in your style using:
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:InfoBar}}, Path=IsError}" Value="True">
<Setter Property="Background" Value="LightPink" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:InfoBar}}, Path=IsError}" Value="False">
<Setter Property="Background" Value="LightYellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
This triggers the background color of the grid based on the IsError value in your InfoBar control.
You give your Control a Background but no child is using it. Two possible solutions:
TemplateBinding
<Grid Margin="4,0,4,0" Background="{TemplateBinding Background}">
DataTrigger with TargetName
<ControlTemplate TargetType="{x:Type local:InfoBar}">
<Grid Name="grid" Margin="4,0,4,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
...
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsError" Value="True" >
<Setter TargetName="grid" Property="Background" Value="LightPink" />
</Trigger>
<Trigger Property="IsError" Value="False" >
<Setter TargetName="grid" Property="Background" Value="LightYellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
In this solution you have to change the order: ControlTemplate.Triggers after Grid declaration.
Try this (Since IsError is DP in your InfoBar and not property of your ControlTemplate)
<DataTrigger Property="{Binding IsError, RelativeSource={RelativeSource
Mode=TemplatedParent}" Value="True">
<Setter Property="Background" Value="LightPink" />
</DataTrigger>
<DataTrigger Property="{Binding IsError, RelativeSource={RelativeSource
Mode=TemplatedParent}" Value="False">
<Setter Property="Background" Value="LightYellow" />
</DataTrigger>