How do I bind a LinearGradientBrush in the GanttControl? - c#

I have a GanttControl with a TaskItemTemplate containing a Grid and a Rectangle which is responsible for the appearence of the tasks. The Rectangle has the properties Fill and Stroke. These properties are being set from StaticResources where the color of the tasks are defined. I try to bind the LinearGradientBrush to the property Color of my model.
There is my Xaml code:
<LinearGradientBrush x:Key="ParentBarFill" StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="White" Offset="0.1" />
<GradientStop Color="Gray" Offset="0.2" />
<GradientStop Color="Black" Offset="0.6" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
** />
<SolidColorBrush x:Key="TaskItemBarStroke" Color="{Binding Color}"/> **<!--There is the Problem too-->**
<!-- Task look and feel styles -->
<!--Transparent-->
<Style TargetType="Thumb" x:Name="TransparentThumb" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Grid>
<Border CornerRadius="2" Background="Transparent" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<flexyGantt:FlexyGantt x:Name="fxgantt" Grid.Row="1" Grid.Column="0" ItemTemplate="{StaticResource TreeTemplate}"
TaskListBinding="{Binding EngineersInterval}" TaskStartTimeBinding="{Binding StartInteval, Mode=TwoWay}"
TaskEndTimeBinding="{Binding FinishInterval, Mode=TwoWay}" ParentTaskStartTimeBinding="{Binding OverallStartTime}"
ParentTaskEndTimeBinding="{Binding OverallEndTime}"
TreeHeaderContent="Teams" CustomSourceListViewTemplate="{StaticResource flexyGanttTableTemplate}"
OverlappedTasksRenderingOptimization="ShrinkHeight" RowHeight="25" TaskTimeChanged="Fxgantt_OnTaskTimeChanged"
>
<flexyGantt:FlexyGantt.TaskItemTemplate>
<DataTemplate>
<Grid ToolTipService.ToolTip="{Binding ToolTipText}">
<Rectangle x:Name="taskBar" HorizontalAlignment="Stretch"
Fill="{StaticResource TaskItemBarFill}" Stroke="{StaticResource TaskItemBarStroke}"
StrokeThickness="1" RadiusX="4" RadiusY="4"/>
<!--Include a thumb with name "dragThumb" to enable drag-moving the task functionality.
ZIndex=2 ensures this is drawn above the Rectangle-->
<Thumb x:Name="dragThumb" Canvas.ZIndex="2" Style="{StaticResource TransparentThumb}" />
<!--Include a thumb with name "resizeThumb" to enable resizing the task functionality
ZIndex=3 ensures this is drawn above the dragThumb-->
<Thumb x:Name="resizeThumb" Canvas.ZIndex="4" HorizontalAlignment="Right" Cursor="SizeWE"
Style="{StaticResource TransparentThumb}" Width="3" />
<!--Include a thumb with name "resizeStartThumb" to enable resizing to the left (changing starttime) functionality
ZIndex=3 ensures this is drawn above the dragThumb-->
<Thumb x:Name="resizeStartThumb" Canvas.ZIndex="3" HorizontalAlignment="Left" Cursor="SizeWE"
Style="{StaticResource TransparentThumb}" Width="3" Height="14"/>
</Grid>
</DataTemplate>
</flexyGantt:FlexyGantt.TaskItemTemplate>
</flexyGantt:FlexyGantt>
How can I bind this? Also me Model :
public class GanttIntervalModel : INotifyPropertyChanged
{
public Color Color
{
get { return _color; }
set
{
if (Equals(value, _color)) return;
_color = value;
OnPropertyChanged(nameof(Color));
}
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Related

WPF button as custom control with text and vector icon

Good evening guys,
I'd really like to have a custom button with text and vector icon.. I searched for something similar but no luck..so I tried by myself to make a custom control but I am not able to make it works: no errors or warnings found but the icon doesn't appear at all.
Here below my code:
Custom control CS:
public class ThButton : Button
{
static ThButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ThButton), new FrameworkPropertyMetadata(typeof(ThButton)));
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(Path), typeof(ThButton), new UIPropertyMetadata(null));
public Path Icon
{
get { return (Path)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty ThLabelProperty =
DependencyProperty.Register("ThLabel", typeof(string), typeof(ThButton), new UIPropertyMetadata(null));
public String ThLabel
{
get { return (String)GetValue(ThLabelProperty); }
set { SetValue(ThLabelProperty, value); }
}
}
generic.xaml (triggers etc. removed since not useful for this):
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlTest">
<Path x:Key="BoatIcon" Fill="Black" Data="M6,6H18V9.96L12,8L6,9.96M3.94,19H4C5.6,19 7,18.12 8,17C9,18.12 10.4,19 12,19C13.6,19 15,18.12 16,17C17,18.12 18.4,19 20,19H20.05L21.95,12.31C22.03,12.06 22,11.78 21.89,11.54C21.76,11.3 21.55,11.12 21.29,11.04L20,10.62V6C20,4.89 19.1,4 18,4H15V1H9V4H6A2,2 0 0,0 4,6V10.62L2.71,11.04C2.45,11.12 2.24,11.3 2.11,11.54C2,11.78 1.97,12.06 2.05,12.31M20,21C18.61,21 17.22,20.53 16,19.67C13.56,21.38 10.44,21.38 8,19.67C6.78,20.53 5.39,21 4,21H2V23H4C5.37,23 6.74,22.65 8,22C10.5,23.3 13.5,23.3 16,22C17.26,22.65 18.62,23 20,23H22V21H20Z" />
<Color x:Key="BackgroundColor1" A="255" R="0" G="133" B="209"/>
<Color x:Key="BackgroundColor2" A="255" R="0" G="61" B="94"/>
<Color x:Key="MouseOverBackgroundColor1" A="255" R="0" G="156" B="231"/>
<Color x:Key="MouseOverBackgroundColor2" A="255" R="0" G="90" B="155"/>
<Color x:Key="MousePressedBackgroundColor1" A="255" R="0" G="98" B="195"/>
<Color x:Key="MousePressedBackgroundColor2" A="255" R="0" G="36" B="72"/>
<Color x:Key="IsNotEnabledBackgroundColor1" A="255" R="233" G="233" B="233"/>
<Color x:Key="IsNotEnabledBackgroundColor2" A="255" R="240" G="240" B="240"/>
<SolidColorBrush x:Key="ThBorderBrush" Color="#ECECEC"></SolidColorBrush>
<Style TargetType="{x:Type local:ThButton}">
<Setter Property="BorderBrush" Value="{StaticResource ThBorderBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ThButton}">
<Border x:Name="t"
Margin="{TemplateBinding Margin}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="6">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop x:Name="BackgroundGradientStop1" Offset="0" Color="{StaticResource BackgroundColor1}"/>
<GradientStop x:Name="BackgroundGradientStop2" Offset="1" Color="{StaticResource BackgroundColor2}"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle Width="20" Height="20" Fill="black" Margin="0,0,0,5">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{TemplateBinding Icon}"/>
</Rectangle.OpacityMask>
</Rectangle>
<Label Content="{TemplateBinding ThLabel}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And finally mainWindow.xaml:
<local:ThButton Width="100" Icon="{StaticResource BoatIcon}" ThLabel="Test"/>
if I put the "{StaticResource BoatIcon}" in place of "{TemplateBinding Icon}" in Visual (generic.xaml) the icon appears so I suppose the problem is all about how I tried to use the DependencyProperty.
This can be done using a custom UserControl quite easily.
First, add your image to your project resources, and make 'Build Type = Resource' in the properties. Do this by selecting the newly added image and right clicking, then setting the above property.
Next, create a UserControl. Here's my XAML
<UserControl x:Class="ListViewDragAndDrop.UCPictureButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ListViewDragAndDrop"
mc:Ignorable="d"
d:DesignHeight="32" d:DesignWidth="128">
<Grid>
<Button Click="Button_Click">
<StackPanel Orientation="Horizontal">
<Image Source="/Resources/solution.png"
Margin="4, 4, 8, 4"/>
<TextBlock Text="Button Text"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</Button>
</Grid>
</UserControl>
Make sure the 'Source' of the image is correct. What's shown above is where it's in my project which is the default.
Then the UserControl code behind:
public partial class UCPictureButton : UserControl
{
public event RoutedEventHandler RoutedButtonClick;
public UCPictureButton()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
RoutedButtonClick?.Invoke(this, e);
}
}
In the button click event, we invoke the RoutedEvent we declared there.
Now on your Main window or wherever you want to use the button:
<local:UCPictureButton Grid.Column="2" Width="120" Height="32">
<i:Interaction.Triggers>
<i:EventTrigger EventName="RoutedButtonClick">
<i:InvokeCommandAction Command="{Binding CmdButtonClick}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</local:UCPictureButton>
The i namespace is the interactivity namespace:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Now all you have to do is in your ViewModel simply hook up a method to the above declared CmdButtonClick command.
I'm using the MVVM Light toolkit and it looks like this:
public RelayCommand CmdButtonClick { get; private set; }
public MainViewModel(IDataService dataService)
{
CmdButtonClick = new RelayCommand(ButtonClick);
}
private void ButtonClick()
{
// Button action
}
Result:

TemplateBinding in ControlTemplate in Style of CustomControl [duplicate]

I'm trying to create a button that behaves similarly to the "slide" button on the iPhone. I have an animation that adjusts the position and width of the button, but I want these values to be based on the text used in the control. Currently, they're hardcoded.
Here's my working XAML, so far:
<CheckBox x:Class="Smt.Controls.SlideCheckBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Smt.Controls"
xmlns:System.Windows="clr-namespace:System.Windows;assembly=PresentationCore"
Name="SliderCheckBox"
mc:Ignorable="d">
<CheckBox.Resources>
<System.Windows:Duration x:Key="AnimationTime">0:0:0.2</System.Windows:Duration>
<Storyboard x:Key="OnChecking">
<DoubleAnimation Storyboard.TargetName="CheckButton"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"
Duration="{StaticResource AnimationTime}"
To="40" />
<DoubleAnimation Storyboard.TargetName="CheckButton"
Storyboard.TargetProperty="(Button.Width)"
Duration="{StaticResource AnimationTime}"
To="41" />
</Storyboard>
<Storyboard x:Key="OnUnchecking">
<DoubleAnimation Storyboard.TargetName="CheckButton"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"
Duration="{StaticResource AnimationTime}"
To="0" />
<DoubleAnimation Storyboard.TargetName="CheckButton"
Storyboard.TargetProperty="(Button.Width)"
Duration="{StaticResource AnimationTime}"
To="40" />
</Storyboard>
<Style x:Key="SlideCheckBoxStyle"
TargetType="{x:Type local:SlideCheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SlideCheckBox}">
<Canvas>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
RecognizesAccessKey="True"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
<Canvas>
<!--Background-->
<Rectangle Width="{Binding ElementName=ButtonText, Path=ActualWidth}"
Height="{Binding ElementName=ButtonText, Path=ActualHeight}"
Fill="LightBlue" />
</Canvas>
<Canvas>
<!--Button-->
<Button Width="{Binding ElementName=CheckedText, Path=ActualWidth}"
Height="{Binding ElementName=ButtonText, Path=ActualHeight}"
Name="CheckButton"
Command="{x:Static local:SlideCheckBox.SlideCheckBoxClicked}">
<Button.RenderTransform>
<TransformGroup>
<TranslateTransform />
</TransformGroup>
</Button.RenderTransform>
</Button>
</Canvas>
<Canvas>
<!--Text-->
<StackPanel Name="ButtonText"
Orientation="Horizontal"
IsHitTestVisible="False">
<Grid Name="CheckedText">
<Label Margin="7 0"
Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:SlideCheckBox}}, Path=CheckedText}" />
</Grid>
<Grid Name="UncheckedText"
HorizontalAlignment="Right">
<Label Margin="7 0"
Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:SlideCheckBox}}, Path=UncheckedText}" />
</Grid>
</StackPanel>
</Canvas>
</Canvas>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource OnChecking}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource OnUnchecking}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Resources>
<CheckBox.CommandBindings>
<CommandBinding Command="{x:Static local:SlideCheckBox.SlideCheckBoxClicked}"
Executed="OnSlideCheckBoxClicked" />
</CheckBox.CommandBindings>
</CheckBox>
And the code behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Smt.Controls
{
public partial class SlideCheckBox : CheckBox
{
public SlideCheckBox()
{
InitializeComponent();
Loaded += OnLoaded;
}
public static readonly DependencyProperty CheckedTextProperty = DependencyProperty.Register("CheckedText", typeof(string), typeof(SlideCheckBox), new PropertyMetadata("Checked Text"));
public string CheckedText
{
get { return (string)GetValue(CheckedTextProperty); }
set { SetValue(CheckedTextProperty, value); }
}
public static readonly DependencyProperty UncheckedTextProperty = DependencyProperty.Register("UncheckedText", typeof(string), typeof(SlideCheckBox), new PropertyMetadata("Unchecked Text"));
public string UncheckedText
{
get { return (string)GetValue(UncheckedTextProperty); }
set { SetValue(UncheckedTextProperty, value); }
}
public static readonly RoutedCommand SlideCheckBoxClicked = new RoutedCommand();
void OnLoaded(object sender, RoutedEventArgs e)
{
Style style = TryFindResource("SlideCheckBoxStyle") as Style;
if (!ReferenceEquals(style, null))
{
Style = style;
}
}
void OnSlideCheckBoxClicked(object sender, ExecutedRoutedEventArgs e)
{
IsChecked = !IsChecked;
}
}
}
The problem comes when I try to bind the "To" attribute in the DoubleAnimations to the actual width of the text, the same as I'm doing in the ControlTemplate. If I bind the values to an ActualWidth of an element in the ControlTemplate, the control comes up as a blank checkbox (my base class). However, I'm binding to the same ActualWidths in the ControlTemplate itself without any problems. Just seems to be the CheckBox.Resources that have a problem with it.
For instance, the following will break it:
<DoubleAnimation Storyboard.TargetName="CheckButton"
Storyboard.TargetProperty="(Button.Width)"
Duration="{StaticResource AnimationTime}"
To="{Binding ElementName=CheckedText, Path=ActualWidth}" />
I don't know whether this is because it's trying to bind to a value that doesn't exist until a render pass is done, or if it's something else. Anyone have any experience with this sort of animation binding?
I've had similar situations in ControlTemplates where I've wanted to bind the "To" attribute to a value (rather than hard-coding it), and I finally found a solution.
Quick side note: If you dig around on the web you'll find examples of people being able to use data binding for the "From" or "To" properties. However, in those examples the Storyboards are not in a Style or ControlTemplate. If your Storyboard is in a Style or ControlTemplate, you'll have to use a different approach, such as this solution.
This solution gets around the freezable issue because it simply animates a double value from 0 to 1. It works with a clever use of the Tag property and a Multiply converter. You use a multibinding to bind to both a desired property and your "scale" (the Tag), which get multiplied together. Basically the idea is that your Tag value is what you animate, and its value acts like a "scale" (from 0 to 1) bringing your desired attribute value to "full scale" once you've animated the Tag to 1.
You can see this in action here. The crux of it is this:
<local:MultiplyConverter x:Key="multiplyConverter" />
<ControlTemplate x:Key="RevealExpanderTemp" TargetType="{x:Type Expander}">
<!-- (other stuff here...) -->
<ScrollViewer x:Name="ExpanderContentScrollView">
<!-- ** BEGIN IMPORTANT PART #1 ... -->
<ScrollViewer.Tag>
<sys:Double>0.0</sys:Double>
</ScrollViewer.Tag>
<ScrollViewer.Height>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</ScrollViewer.Height>
<!-- ...end important part #1. -->
<ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/>
</ScrollViewer>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<!-- ** BEGIN IMPORTANT PART #2 (make TargetProperty 'Tag') ... -->
<DoubleAnimation Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="1"
Duration="0:0:0.4"/>
<!-- ...end important part #2 -->
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
With this value converter:
public class MultiplyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double result = 1.0;
for (int i = 0; i < values.Length; i++)
{
if (values[i] is double)
result *= (double)values[i];
}
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new Exception("Not implemented");
}
}
As far as I know, you can't bind the animation to/from because the animation has to be freezable.
I like #Jason Frank's solution. However it is even easier and less error-prone if you don't use the Tag, but instead e.g. the Width property of an empty dummy Border element. It is a native double property, so no need for <sys:Double> syntax and you can name the Border just like you would do with a variable like so:
<!-- THIS IS JUST USED FOR SLIDING ANIMATION MATH -->
<!-- animated Border.Width From 0 to 1 -->
<Border x:Name="Var_Animation_0to1" Width="0"/>
<!-- animated Border.Width From 0 to (TotalWidth-SliderWidth) -->
<Border x:Name="Var_Slide_Length">
<Border.Width>
<MultiBinding Converter="{mvvm:MathConverter}" ConverterParameter="a * (b-c)">
<Binding ElementName="Var_Animation_0to1" Path="Width"/>
<Binding ElementName="BackBorder" Path="ActualWidth"/>
<Binding ElementName="Slider" Path="ActualWidth"/>
</MultiBinding>
</Border.Width>
</Border>
That makes the bindings much more readable.
The Animation is always 0..1, as Jason pointed out:
<BeginStoryboard Name="checkedSB">
<Storyboard Storyboard.TargetProperty="Width" Storyboard.TargetName="Var_Animation_0to1">
<DoubleAnimation To="1" Duration="00:00:00.2"/>
</Storyboard>
</BeginStoryboard>
Then bind whatever you want to animate to the Width of the dummy border. This way you can even chain converters to each other like so:
<Border x:Name="Slider" HorizontalAlignment="Left"
Margin="{Binding ElementName=Var_Slide_Length, Path=Width, Converter={StaticResource DoubleToThickness}, ConverterParameter=x 0 0 0}"/>
Combined with the MathConverter you can do almost anything in styles:
https://www.codeproject.com/Articles/239251/MathConverter-How-to-Do-Math-in-XAML
I implemented this exact thing.
<UserControl x:Class="YOURNAMESPACE.UserControls.SliderControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:YOURNAMESPACE.UserControls"
xmlns:converter="clr-namespace:YOURNAMESPACE.ValueConverters"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
SizeChanged="UserControl_SizeChanged">
<UserControl.Resources>
<converter:MathConverter x:Key="mathConverter" />
<LinearGradientBrush x:Key="CheckedBlue" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#e4f5fc" Offset="0" />
<GradientStop Color="#e4f5fc" Offset="0.1" />
<GradientStop Color="#e4f5fc" Offset="0.1" />
<GradientStop Color="#9fd8ef" Offset="0.5" />
<GradientStop Color="#9fd8ef" Offset="0.5" />
<GradientStop Color="#bfe8f9" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckedOrange" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFCA6A13" Offset="0" />
<GradientStop Color="#FFF67D0C" Offset="0.1" />
<GradientStop Color="#FFFE7F0C" Offset="0.1" />
<GradientStop Color="#FFFA8E12" Offset="0.5" />
<GradientStop Color="#FFFF981D" Offset="0.5" />
<GradientStop Color="#FFFCBC5A" Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="CheckedOrangeBorder" Color="#FF8E4A1B" />
<SolidColorBrush x:Key="CheckedBlueBorder" Color="#FF143874" />
<Style x:Key="CheckBoxSlider" TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}" >
<DockPanel x:Name="dockPanel"
Width="{TemplateBinding ActualWidth}"
Height="{TemplateBinding Height}" >
<DockPanel.Resources>
<Storyboard x:Key="ShowRightStoryboard">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="ShowLeftStoryboard" >
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="slider"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
>
<SplineDoubleKeyFrame x:Name="RightHalfKeyFrame" KeyTime="00:00:00.1000000" Value="300" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</DockPanel.Resources>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
ContentTemplate="{TemplateBinding ContentTemplate}"
RecognizesAccessKey="True"
VerticalAlignment="Center" />
<Grid>
<Border x:Name="BackgroundBorder" BorderBrush="#FF939393" BorderThickness="1" CornerRadius="3"
Width="{TemplateBinding ActualWidth}"
Height="{TemplateBinding Height}" >
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFB5B5B5" Offset="0" />
<GradientStop Color="#FFDEDEDE" Offset="0.1" />
<GradientStop Color="#FFEEEEEE" Offset="0.5" />
<GradientStop Color="#FFFAFAFA" Offset="0.5" />
<GradientStop Color="#FFFEFEFE" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock x:Name="LeftTextBlock" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:SliderControl}}, Path=LeftText, Mode=TwoWay}" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock x:Name="RightTextBlock" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:SliderControl}}, Path=RightText, Mode=TwoWay}" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
<Border x:Name="slider"
BorderBrush="#FF939393"
HorizontalAlignment="Left"
Width="{TemplateBinding ActualWidth, Converter={StaticResource mathConverter}, ConverterParameter=/2}"
Height="{TemplateBinding Height}"
BorderThickness="1"
CornerRadius="3"
RenderTransformOrigin="0.5,0.5" Margin="0"
>
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1" />
<SkewTransform AngleX="0" AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="{TemplateBinding ActualWidth, Converter={StaticResource mathConverter}, ConverterParameter=/2}" Y="0" />
</TransformGroup>
</Border.RenderTransform>
<Border.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFF0F0F0" Offset="0" />
<GradientStop Color="#FFCDCDCD" Offset="0.1" />
<GradientStop Color="#FFFBFBFB" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<DockPanel Background="Transparent" LastChildFill="False">
<Viewbox x:Name="SlideRight" Stretch="Uniform" Width="28" Height="28" DockPanel.Dock="Right" Margin="0,0,50,0" >
<Path Stretch="Fill" Fill="{DynamicResource TextBrush}">
<Path.Data>
<PathGeometry Figures="m 27.773437 48.874779 -8.818359 9.902343 -4.833984 0 8.847656 -9.902343 -8.847656 -10.019532 4.833984 0 z m -11.396484 0 -8.7597655 9.902343 -4.9804687 0 9.0234372 -9.902343 -9.0234372 -10.019532 4.9804687 0 z" FillRule="NonZero"/>
</Path.Data>
</Path>
</Viewbox>
<Viewbox x:Name="SlideLeft" Stretch="Uniform" Width="28" Height="28" DockPanel.Dock="Left" Margin="50,0,0,0" >
<Path Stretch="Fill" Fill="{DynamicResource TextBrush}">
<Path.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleX="-1"/>
</TransformGroup>
</Path.LayoutTransform>
<Path.Data>
<PathGeometry Figures="m 27.773437 48.874779 -8.818359 9.902343 -4.833984 0 8.847656 -9.902343 -8.847656 -10.019532 4.833984 0 z m -11.396484 0 -8.7597655 9.902343 -4.9804687 0 9.0234372 -9.902343 -9.0234372 -10.019532 4.9804687 0 z" FillRule="NonZero"/>
</Path.Data>
</Path>
</Viewbox>
</DockPanel>
</Border>
</Grid>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="BackgroundBorder" Property="Background" Value="{StaticResource CheckedOrange}" />
<Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="{StaticResource CheckedOrangeBorder}" />
<Setter TargetName="SlideRight" Property="Visibility" Value="Collapsed" />
<Setter TargetName="SlideLeft" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="BackgroundBorder" Property="Background" Value="{StaticResource CheckedBlue}" />
<Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="{StaticResource CheckedBlueBorder}" />
<Setter TargetName="SlideRight" Property="Visibility" Value="Visible" />
<Setter TargetName="SlideLeft" Property="Visibility" Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox x:Name="checkBox"
Style="{StaticResource CheckBoxSlider}"
HorizontalAlignment="Stretch"
DockPanel.Dock="Top"
Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:SliderControl}}, Path=Height, Mode=TwoWay}"
IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:SliderControl}}, Path=IsLeftVisible, Mode=TwoWay}"
Checked="CheckBox_Checked"
Unchecked="CheckBox_Unchecked"
/>
</Grid>
</UserControl>
code behind.
namespace YOURNAMESPACE.UserControls
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
/// <summary>
/// Interaction logic for SliderControl.xaml
/// </summary>
public partial class SliderControl : UserControl
{
public static readonly DependencyProperty IsLeftVisibleProperty =
DependencyProperty.RegisterAttached(
"IsLeftVisible",
typeof(bool),
typeof(SliderControl),
new UIPropertyMetadata(true, IsLeftVisibleChanged));
public static readonly DependencyProperty LeftTextProperty =
DependencyProperty.RegisterAttached(
"LeftText",
typeof(string),
typeof(SliderControl),
new UIPropertyMetadata(null, LeftTextChanged));
public static readonly DependencyProperty RightTextProperty =
DependencyProperty.RegisterAttached(
"RightText",
typeof(string),
typeof(SliderControl),
new UIPropertyMetadata(null, RightTextChanged));
/// <summary>
/// Initializes a new instance of the <see cref="SliderControl"/> class.
/// </summary>
public SliderControl()
{
this.InitializeComponent();
}
public string LeftText { get; set; }
public string RightText { get; set; }
[AttachedPropertyBrowsableForType(typeof(SliderControl))]
public static bool GetIsLeftVisible(SliderControl sliderControl)
{
return (bool)sliderControl.GetValue(IsLeftVisibleProperty);
}
[AttachedPropertyBrowsableForType(typeof(SliderControl))]
public static string GetLeftText(SliderControl sliderControl)
{
return (string)sliderControl.GetValue(LeftTextProperty);
}
public static void SetIsLeftVisible(SliderControl sliderControl, bool value)
{
sliderControl.SetValue(IsLeftVisibleProperty, value);
}
public static void IsLeftVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SliderControl slider = d as SliderControl;
if ((bool)e.NewValue == true)
{
slider.RunAnimation("ShowLeftStoryboard");
}
else
{
slider.RunAnimation("ShowRightStoryboard");
}
}
[AttachedPropertyBrowsableForType(typeof(SliderControl))]
public static string GetRightText(SliderControl sliderControl)
{
return (string)sliderControl.GetValue(RightTextProperty);
}
public static void SetLeftText(SliderControl sliderControl, string value)
{
sliderControl.SetValue(LeftTextProperty, value);
}
public static void SetRightText(SliderControl sliderControl, string value)
{
sliderControl.SetValue(RightTextProperty, value);
}
private static void LeftTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SliderControl slider = d as SliderControl;
slider.LeftText = e.NewValue as string;
}
private static void RightTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SliderControl slider = d as SliderControl;
slider.RightText = e.NewValue as string;
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
this.checkBox.Width = e.NewSize.Width;
CheckBox cb = this.checkBox;
var controlTemplate = cb.Template;
DockPanel dockPanel = controlTemplate.FindName("dockPanel", cb) as DockPanel;
Storyboard story = dockPanel.Resources["ShowLeftStoryboard"] as Storyboard;
DoubleAnimationUsingKeyFrames dk = story.Children[0] as DoubleAnimationUsingKeyFrames;
SplineDoubleKeyFrame sk = dk.KeyFrames[0] as SplineDoubleKeyFrame;
// must manipulate this in code behind, binding does not work,
// also it cannot be inside of a control template
// because storyboards in control templates become frozen and cannot be modified
sk.Value = cb.Width / 2;
if (cb.IsChecked == true)
{
story.Begin(cb, cb.Template);
}
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
this.RunAnimation("ShowLeftStoryboard");
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
this.RunAnimation("ShowRightStoryboard");
}
private void RunAnimation(string storyboard)
{
CheckBox cb = this.checkBox;
var controlTemplate = cb.Template;
DockPanel dockPanel = controlTemplate.FindName("dockPanel", cb) as DockPanel;
if (dockPanel != null)
{
Storyboard story = dockPanel.Resources[storyboard] as Storyboard;
DoubleAnimationUsingKeyFrames dk = story.Children[0] as DoubleAnimationUsingKeyFrames;
SplineDoubleKeyFrame sk = dk.KeyFrames[0] as SplineDoubleKeyFrame;
story.Begin(cb, cb.Template);
}
}
}
}
IValueConverter
namespace YOURNAMESPACE.ValueConverters
{
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
/// <summary>
/// Does basic math operations, eg. value = 60 parameter = "*2 + 1", result = 121
/// </summary>
/// <seealso cref="System.Windows.Data.IValueConverter" />
[ValueConversion(typeof(double), typeof(double))]
public class MathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double d = (double)value;
string mathExpression = d.ToString() + parameter;
if (mathExpression.Contains("^"))
{
throw new Exception("Doesn't handle powers or square roots");
}
DataTable table = new DataTable();
table.Columns.Add("expression", typeof(string), mathExpression);
DataRow row = table.NewRow();
table.Rows.Add(row);
double ret = double.Parse((string)row["expression"]);
if (ret <= 0)
{
return 1d;
}
return ret;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// not implemented
return null;
}
}
}
example usage:
<chart:SliderControl x:Name="sliderControl"
LeftText="{Binding Path=LeftTextProperty}"
RightText="{Binding Path=RightTextProperty}"
Grid.Row="0"
IsLeftVisible="{Binding Path=IsLeftVisible, Mode=TwoWay}"
Height="35" />

getting textBlock from list view dynamically

I have a ListView which contain 2 textBlocks as a listview Item
I want to color the textBlocks dynamically
how can I get do the textblock?
will appreciate an example.
Thanks you for your support
attaching My XAML:
<ListView x:Name="LV" ItemsSource= "{Binding Lggv}" SelectionChanged="dataGridData_SelectionChanged" ItemContainerStyle="{StaticResource ListViewItemStyle}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel >
<Border BorderThickness="1" BorderBrush="Black">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tbHeader" Text="{Binding Info }" AllowDrop="True" FontWeight="Bold" Grid.Column="2" >
<TextBlock.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFCEE6C6" Offset="0.008"/>
<GradientStop Color="#FF9ECF8C" Offset="0.987"/>
</LinearGradientBrush>
</TextBlock.Background>
</TextBlock>
</Grid>
</Border>
<Grid x:Name="GridData" >
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFC5DDFF" Offset="0"/>
<GradientStop Color="#FFA8C8F7" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderThickness="2" BorderBrush="Black">
<TextBlock Text="{Binding DateTime}" ></TextBlock>
</Border>
<Border Grid.Column="1" BorderThickness="2" BorderBrush="Black">
<TextBlock Text="{Binding ComPort}"></TextBlock>
</Border>
<Border Grid.Column="2" BorderThickness="2" BorderBrush="Black">
<TextBlock Text="{Binding Data}" ></TextBlock>
</Border>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The best way to do this is with a IValueConverter
as this allows you to keep your view and viewModel seperate, though if you don't care about that #sasanaf answer is perfertly correct
here is an example of a simple Brush based converter
public class PriorityConverter : IValueConverter
{
public Brush HighBrush { get; set; }
public Brush LowBrush { get; set; }
public Brush MediumBrush { get; set; }
public Brush DefaultBrush { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var priority = value as Priority?;
if (priority.HasValue)
{
switch (priority.Value)
{
case Priority.High:
return HighBrush;
case Priority.Medium:
return MediumBrush;
case Priority.Low:
return LowBrush;
default:
return DefaultBrush;
}
}
else
throw new InvalidCastException($"{value} is not a Priority");
}
You would then add the converter as a resource to your App,
<local:PriorityConverter x:Key="PriorityConverter" >
<local:PriorityConverter.DefaultBrush>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ControlColorKey}}"/>
</local:PriorityConverter.DefaultBrush>
<local:PriorityConverter.HighBrush>
<LinearGradientBrush>
<GradientStop Color="Red" Offset="0.5"/>
<GradientStop Color="Yellow" />
</LinearGradientBrush>
</local:PriorityConverter.HighBrush>
<local:PriorityConverter.MediumBrush>
<SolidColorBrush Color="Blue"/>
</local:PriorityConverter.MediumBrush>
<local:PriorityConverter.LowBrush>
<SolidColorBrush Color="Green"/>
</local:PriorityConverter.LowBrush>
</local:PriorityConverter>
and finally use it on your binding
<TextBlock Background="{Binding Priority, Converter={StaticResource PriorityConverter}}" />
If you are having a MVVM approach, i would set the colors in the ViewModel and bind them to the properties.
Edit:
Textblock like this:
<TextBlock DataContext="ViewModel"
Background="{Binding SpecificColor}">
</TextBlock>
And in ViewModel you can specifiy at initialization or at any specific event wich color you would like.
For Example :
private Brush m_SpecificColor;
public Brush SpecificColor
{
get { return m_SpecificColor; }
set
{
m_SpecificColor = value;
OnPropertyChanged("SpecificColor");
}
}
private void SetColor()
{
SpecificColor = (Brush)new BrushConverter().ConvertFromString("Green");
}
I guess you want to change the colour dynamically based on some property of the object (the class with the "Info", "DateTime", "ComPort" and "Data" properties) in your Lggv source collection.
You could then use a style with a DataTrigger that binds to a property of this class, i.e. the the type T (again this is the one with the "Info", "DateTime", "ComPort" and "Data" properties) of the IEnumerable<T> (Lggv) source collection that you bind to:
<TextBlock x:Name="tbHeader" Text="{Binding Info}" AllowDrop="True" FontWeight="Bold" Grid.Column="2">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Background">
<Setter.Value>
<!-- this is the default background-->
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFCEE6C6" Offset="0.008"/>
<GradientStop Color="#FF9ECF8C" Offset="0.987"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Style.Triggers>
<!-- This trigger changes the background to green when the "Info" property of your data object returns "Some info..." -->
<DataTrigger Binding="{Binding Info}" Value="Some info...">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush>Green</SolidColorBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
You can use IValueConverter to convert property to background color. Below is an example.
class BackgroundColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush();
if (value != null )
{
string strValue = value.ToString();
myLinearGradientBrush.StartPoint = new System.Windows.Point(0, 0);
myLinearGradientBrush.EndPoint = new System.Windows.Point(1, 1);
switch (strValue)
{
case "Match1":
myLinearGradientBrush.GradientStops.Add(new GradientStop(Colors.Yellow, 0.0));
myLinearGradientBrush.GradientStops.Add(new GradientStop(Colors.Red, 0.25));
break;
case "Match2":
myLinearGradientBrush.GradientStops.Add(new GradientStop(Colors.Blue , 0.0));
myLinearGradientBrush.GradientStops.Add(new GradientStop(Colors.BlueViolet, 0.25));
break;
default:
myLinearGradientBrush.GradientStops.Add(new GradientStop(Colors.Green , 0.0));
myLinearGradientBrush.GradientStops.Add(new GradientStop(Colors.GreenYellow, 0.25));
break;
}
}
return myLinearGradientBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Declare value convert in resource as below.
<Window.Resources>
<local:BackgroundColorConverter x:Key="BackgroundColorConverter"/>
</Window.Resources>
Below is the coder of Xaml.
<TextBlock x:Name="tbHeader" Text="{Binding Info }" Background="{Binding Path=property, Converter={StaticResource BackgroundColorConverter}}" AllowDrop="True" FontWeight="Bold" Grid.Column="2"/>
another approach if you want to use resource. You can define color in windows or user control resource. After this you will have to use IMultiValueConverter. Pass you property and windows or user control to MultiValueConverter. You need to use relative source to get windows or usercontrol in binding. Then you can return the resource as per the matching condition.
Personally I'd do this with a DataTrigger:
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFCEE6C6" Offset="0.008"/>
<GradientStop Color="#FF9ECF8C" Offset="0.987"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding YourProperty}" Value="YourPropertyValue">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Red" Offset="0.008"/>
<GradientStop Color="Orange" Offset="0.987"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
You don't then have to have a class defined to do what is a relatively simple task.

Binding Shape.Stroke to ResourceDictionary according an enum

I've created this ResourcesDictionary:
<LinearGradientBrush x:Key="OffStroke" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF007226" Offset="0"/>
<GradientStop Color="#FF003C15" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="OnStroke" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF6BBF8A" Offset="0"/>
<GradientStop Color="#FF007A27" Offset="0.306"/>
</LinearGradientBrush>
then i've created the following enum in codeBehind:
/// <summary>
/// Enumerator
/// </summary>
public enum Strokes
{
/// <summary>
/// off (value 0)
/// </summary>
Off = 0x00,
/// <summary>
/// on (value 1)
/// </summary>
On = 0x01,
}
and I've put two ellipse inside the UserControl xaml side.
<Viewbox x:Name="ViewBoxRoot">
<Grid x:Name="GridRoot" Width="256" Height="256">
<Ellipse x:Name="OnStroke" Stroke={StaticResource OnStroke}/>
<Ellipse x:Name="OffStroke" Stroke="{StaticResource OffStroke}"/>
</Grid>
</Viewbox>
and last I've insert the follow properties:
public static readonly DependencyProperty StrokeXProperty =
DependencyProperty.Register("StrokeX", typeof(Enums.Strokes), typeof(MyUserControl), new PropertyMetadata(Enums.Strokes.Off));
public Enums.Strokes StrokeX
{
get { return (Enums.Strokes)GetValue(myUserControl.StrokeXProperty); }
set
{
SetValue(myUserControl.StrokeXProperty, value);
OnPropertyChanged("StrokeX");
}
}
There's a possibility to binding the Ellipse Stroke property to stroke ResourceDictionary According to enum value?
Thanks in advance
If you define your gradient brushes in the resource dictionary like this:
xmlns:enums="clr-namespace:MyNamespace.Enums" ...
<LinearGradientBrush x:Key="{x:Static enums:Strokes.Off}" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF007226" Offset="0"/>
<GradientStop Color="#FF003C15" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="{x:Static enums:Strokes.On}" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF6BBF8A" Offset="0"/>
<GradientStop Color="#FF007A27" Offset="0.306"/>
</LinearGradientBrush>
Now you can use these resource keys directly:
<Ellipse x:Name="OnStroke" Stroke="{StaticResource {x:Static enums:Strokes.On}}"/>
<Ellipse x:Name="OffStroke" Stroke="{StaticResource {x:Static enums:Strokes.On}}"/>
However, to bind to a dependency property is a bit more tricky. If you define your strokes the App.xaml resource dictionary, then you can create a IValueConverter along the lines of this:
public class ApplicationResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Application.Current.Resources[value];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Now you can bind to the property value using the converter, like this:
MyControl.xaml
<UserControl x:Class="MyNamespace.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace"
xmlns:converters="clr-namespace:MyNamespace.Converters">
<UserControl.Resources>
<converters:ApplicationResourceConverter x:Key="ApplicationResourceConverter"/>
</UserControl.Resources>
<StackPanel Grid.Row="1" Grid.Column="2">
<Ellipse Stroke="{Binding StrokeX, RelativeSource={RelativeSource AncestorType=local:MyControl}, Converter={StaticResource ApplicationResourceConverter}}"
StrokeThickness="5"
Fill="AliceBlue"
Width="100"
Height="100"
Margin="0 0 0 20"/>
<StackPanel Orientation="Horizontal">
<Button Click="OnButton_Click">On</Button>
<Button Click="OffButton_Click">Off</Button>
</StackPanel>
</StackPanel>
</UserControl>
MyControl.xaml.cs
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
public static readonly DependencyProperty StrokeXProperty =
DependencyProperty.Register("StrokeX", typeof(Enums.Strokes), typeof(MyControl), new PropertyMetadata(Enums.Strokes.Off));
public Enums.Strokes StrokeX
{
get { return (Enums.Strokes)GetValue(StrokeXProperty); }
set
{
SetValue(StrokeXProperty, value);
}
}
private void OnButton_Click(object sender, RoutedEventArgs e)
{
this.StrokeX = Enums.Strokes.On;
}
private void OffButton_Click(object sender, RoutedEventArgs e)
{
this.StrokeX = Enums.Strokes.Off;
}
}
Alternatively, you could forgo any bindings and just use triggers to accomplish roughly the same thing. Here's an example style that shows how you might accomplish that:
Themes/Generic.xaml
xmlns:enums="clr-namespace:MyNamespace.Enums" ...
<LinearGradientBrush x:Key="{x:Static enums:Strokes.Off}" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF007226" Offset="0"/>
<GradientStop Color="#FF003C15" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="{x:Static enums:Strokes.On}" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF6BBF8A" Offset="0"/>
<GradientStop Color="#FF007A27" Offset="0.306"/>
</LinearGradientBrush>
<Style x:Key="{x:Type local:MyControl}" TargetType="local:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyControl">
<StackPanel Grid.Row="1" Grid.Column="2">
<Ellipse Name="_ellipse"
StrokeThickness="5"
Fill="AliceBlue"
Width="100"
Height="100"
Margin="0 0 0 20"/>
<StackPanel Orientation="Horizontal">
<Button Click="OnButton_Click">On</Button>
<Button Click="OffButton_Click">Off</Button>
</StackPanel>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="StrokeX" Value="{x:Static enums:Strokes.On}">
<Setter TargetName="_ellipse" Property="Stroke" Value="{DynamicResource {x:Static enums:Strokes.On}}"/>
</Trigger>
<Trigger Property="StrokeX" Value="{x:Static enums:Strokes.Off}">
<Setter TargetName="_ellipse" Property="Stroke" Value="{DynamicResource {x:Static enums:Strokes.Off}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
this is how to use in a control that will be used in a window.
put this line in constructor of UserControl before InitializeComponent
suppose that your ResourcesDictionary file name is StrokeResources.xaml
//merge the control resources used to current application
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary(){Source = new Uri("/DLLNameSpace;component/ResourcesDictionaries/StrokeResources.xaml", UriKind.RelativeOrAbsolute)});
then modify the xaml code :
<Ellipse Stroke="{Binding StrokeX, Converter={StaticResource ApplicationResourceConverter}}"/>
in this way the resources was add to actual application...

Using observablecollection with buttons

I have an observablecollection to create buttons the problem is that each of these buttons call the same event handler. i am trying to make it so that each button has their own unique id so that they can be distinguished from one another. the code used to create the button elements is
public class button
{
public bool IsEmpty { get; set; }
public int ID {get; set;}
public button(int button_Number)
{
IsEmpty = true;
ID = button_Number;
}
}
I is added to a observablecollection in the following code
ButtonCollection = new ObservableCollection<cChipVM>();
for ( int i = 0 ; i < iNumChips ; ++i )
{
ButtonCollection.Add( new button(i) );
}
the xml for the button is the following
<DataTemplate x:Key="ButtonTemplate">
<Button x:Name="Button" Uid="{Binding Path=ID}" Click="Button_Click" BorderBrush="Black" BorderThickness="1" Margin="7" Width="25" Height="25" ClickMode="Press" Opacity="0.9" Focusable="False" IsHitTestVisible="True" AllowDrop="True" IsTabStop="False">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEmpty}" Value="false">
<Setter Property="Button.Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF5ED426" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsEmpty}" Value="true">
<Setter Property="Button.Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF1766F0" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
When it tries to set the Uid with this method the system crashes, any recommendation how to fix this or any other solution where each button can have a unique ID
You can use Button.Tag property to store ID and in the handler inspect the value of Tag
<Button Tag="{Binding Path=ID}" Click="Button_Click" BorderBrush="Black" BorderThickness="1" Margin="7" Width="25" Height="25" ClickMode="Press" Opacity="0.9" Focusable="False" IsHitTestVisible="True" AllowDrop="True" IsTabStop="False">
UPDATE : Button click handler
public void Button_Click(object sender,EventArgs e)
{
var myButton = (Button)sender;
int id = Convert.ToInt32(myButton.Tag);
}

Categories

Resources