Binding Boder.Background to LinearGradientBrush from Resource Dictionary - c#

I'd like to Bind the Background of a Border Property to elements in a list.
I have a Dictionary holding the follwing:
<LinearGradientBrush x:Key="ConfigurationItemBackground" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFAABBCC" Offset="1"/>
<GradientStop Color="#FFCCDDEE" Offset="0.7"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="NavigationItemBackground" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD97825" Offset="1"/>
<GradientStop Color="#FFFF9A2E" Offset="0.7"/>
</LinearGradientBrush>
Now I fill a ObservableCollection holding Objects that contain a Property called "BackgroundStyle". When I fill a list box with styled background I'd like to bind the Background to "BackgroundStyle"
<Border x:Name="Border" BorderThickness="1" CornerRadius="4" Width="120" Height="80"
VerticalAlignment="Center" HorizontalAlignment="Center" Padding="4"
BorderBrush="Black" Background="{Binding Path=BackgroundStyle}">
This works well, if BackgroundStyle="Red" or "Green" but it won't work if I use "ConfigurationItemBackground".
Any suggestions?
Thanks for your help ;)
-Tim-

You can't do exactly what you're trying to do, which is essentially to use data binding to store the key of a resource within your bound object. The closest you can get would be the answer to this question, which basically uses a ValueConverter to get the resource from the application's resources.
Unfortunately, this won't work with what you want to do, which is use a local resource. For that, you'd be better off writing your own custom ValueConverter that converts your string value into a brush.
You could do something generic like this:
[ValueConversion(typeof(string), typeof(object))]
public class ResourceKeyConverter : IValueConverter
{
public ResourceKeyConverter()
{
Resources = new ResourceDictionary();
}
public ResourceDictionary Resources { get; private set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Resources[(string)value];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
Then use it like this:
<Window.Resources>
<my:ResourceKeyConverter x:Key="keyConverter">
<ResourceKeyConverter.Resources>
<LinearGradientBrush x:Key="ConfigurationItemBackground" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFAABBCC" Offset="1"/>
<GradientStop Color="#FFCCDDEE" Offset="0.7"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="NavigationItemBackground" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD97825" Offset="1"/>
<GradientStop Color="#FFFF9A2E" Offset="0.7"/>
</LinearGradientBrush>
</ResourceKeyConverter.Resources>
</my:ResourceKeyConverter>
</Window.Resources>
...
<Border Background="{Binding BackgroundStyle, Converter={StaticResource keyConverter}}">
</Border>
(I'm at home and don't have Visual Studio in front of me, so this might require some tweaking, but it should be largely correct).

Related

RadCartesianChart Setting

I use Telerik component for serial port plot data on chart, I need to know how can i have more space between X-Axis item now x-axis show compressed and i need to know if the plot point increase how can add chart auto scroll,this is my XAML code :
<telerik:RadCartesianChart x:Name="myChart" ScrollViewer.HorizontalScrollBarVisibility="Auto">
<telerik:RadCartesianChart.Grid>
<telerik:CartesianChartGrid/>
</telerik:RadCartesianChart.Grid>
<telerik:RadCartesianChart.HorizontalAxis>
<telerik:CategoricalAxis IsStepRecalculationOnZoomEnabled="True" LabelOffset="0" LastLabelVisibility="Visible" LineThickness="1" MajorTickOffset="0" MajorTickLength="5" MajorTickInterval="1" PlotMode="BetweenTicks" SmartLabelsMode="None" TickThickness="1" ZIndex="0"/>
</telerik:RadCartesianChart.HorizontalAxis>
<telerik:RadCartesianChart.VerticalAxis>
<telerik:LinearAxis BorderThickness="0,4,0,0">
<telerik:LinearAxis.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FF0E0EF5" Offset="1"/>
</LinearGradientBrush>
</telerik:LinearAxis.BorderBrush>
<telerik:LinearAxis.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FFE41F1F" Offset="1"/>
</LinearGradientBrush>
</telerik:LinearAxis.Background>
</telerik:LinearAxis>
</telerik:RadCartesianChart.VerticalAxis>
</telerik:RadCartesianChart>
I was push my project to Github
I found my answer, Add those tag to radCartesianChart root element
ScrollViewer.HorizontalScrollBarVisibility="Auto"
HorizontalZoomRangeStart="0.9"
HorizontalZoomRangeEnd="1"
Complete format :
<telerik:RadCartesianChart
x:Name="myChart"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
HorizontalZoomRangeStart="0.9"
HorizontalZoomRangeEnd="1"
Margin="0,0,445,162">

WPF Border Color Binding to parent Controls Tag

I have a problem where I have to bind to Tag property. But don't know what will come here.
<Border x:Name="BorderStatus" CornerRadius="2" Tag="Transparent">
<Border.Background>
<LinearGradientBrush>
<GradientStop Color="{Binding Tag, ????}" Offset="0"/>
<GradientStop Color="{Binding Tag, ????}" Offset="0.47"/>
<GradientStop Color="Red" Offset="0.77"/>
<GradientStop Color="DarkRed" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
</Border>
This is done cause there are triggers which will change the tag property.
We can bind with ElementName but is there any other way?
Two ways of accomplishing your goal I can think of are these:
I. Use Binding.ElementName property:
Color="{Binding Tag, ElementName=BorderStatus}"
II. Use RelativeSource in FindAncestor mode:
Color="{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"

Execution order of element properties in xaml

Is there a way to execute attached behavior last, after initialization of list properties in following example
<LinearGradientBrush local:FreezeBehavior.IsFrozen="True">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
It can be done like this
<GradientStopCollection x:Key="SomeKey">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</GradientStopCollection>
<LinearGradientBrush GradientStops="{StaticResource SomeKey}" local:FreezeBehavior.IsFrozen="True"/>
But it will require to create dozens of unnecessary ResourceDictionary entries.
P.S.: related question (in case someone see this as duplicate, then vote close it instead of this one, here I already know the problem and it's more clearly described).
I guess execution flow is based on XAML Parser, and in parse properties as they appear. So you can try to reorder declarations of properties. Something like this:
<LinearGradientBrush>
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
<local:FreezeBehavior.IsFrozen>True</local:FreezeBehavior.IsFrozen>
</LinearGradientBrush>
May be you'll have to use <sys:Bool>True</sys:Bool> as value of FreezeBehavior.IsFrozen

How to allow default value when using binding for custom control

All, I am working on a custom control of ours that has a Border with a Background set to the below
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFF7F7F7" Offset="0.164" />
<GradientStop Color="#FFDBDBDB" Offset="0.664" />
<GradientStop Color="#FFB3B3B3" Offset="0.978" />
</LinearGradientBrush>
However, I want to allow the user to override this. I created a dependency property of type Brush, however I cannot figure out how to bind to the Background, while still having this default in the XAML. Is this even possible?
Take a look at the TemplateBinding Markup Extension
<Style TargetType="{x:Type your:YourControl}">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFF7F7F7" Offset="0.164" />
<GradientStop Color="#FFDBDBDB" Offset="0.664" />
<GradientStop Color="#FFB3B3B3" Offset="0.978" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
Then in some part of your default ControlTemplate:
<Border Background="{TemplateBinding Background}">
....
</Border>
This will allow the consumer to override the default Background, while maintaining the Style-defined one:
<your:YourControl/> <!-- Will use default Background -->
<your:YourControl Background="Green"/> <!-- will have Green background -->

Color inversion in XAML

In my WP8 application I want to make a color inversion effect. I have no idea what tools I should use so I'll just explain what I want in a very general terms.
How it is supposed to work: say I have a UserControl that consists of black rectangle and some white text on top of it. I want to apply something to that user control that will invert colors of a part of UserControl that it covers. Some invisible rectangle that spans say 50% of UserControl and in that area background will be white and text will be black. I want it to be dynamic so I can change the area it covers at runtime.
Here's an image to illustrate this:
Inversion effect applied to a half of control.
I believe it's possible to achieve this by using two controls with same text, inverted colors and opacity mask but I wonder if this can be done in a more clean and direct way?
I think what you're looking for ideally would either be two TextBlocks with OpacityMask applied to the one on top like;
<Grid MaxWidth="100">
<TextBlock Text="Hey check it out we can change object gradients! yay!" Foreground="Red"
TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="Hey check it out we can change object gradients! yay!" Foreground="Blue"
TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.OpacityMask>
<LinearGradientBrush StartPoint="0.1,0.1" EndPoint="0.75,0.75">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.322" Color="Black"/>
<GradientStop Offset="0.739" Color="Transparent"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</TextBlock.OpacityMask>
</TextBlock>
</Grid>
Or you could just apply a LinearGradientBrush directly to the Foreground (or Background of other element) itself like;
<Border Width="100" Height="50">
<Border.Background>
<LinearGradientBrush StartPoint="0.062,0.552" EndPoint="0.835,0.548">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.5" Color="White"/>
<GradientStop Offset="0.5" Color="Black"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<TextBlock Text="Hello World!" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.Foreground>
<LinearGradientBrush StartPoint="0.1,0.1" EndPoint="0.75,0.75">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.5" Color="Black"/>
<GradientStop Offset="0.5" Color="White"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>
</Border>
or gettin 80's style fancy;
<Border Width="100" Height="50">
<Border.Background>
<LinearGradientBrush StartPoint="0.472,0.047" EndPoint="0.47,0.942">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.541" Color="White"/>
<GradientStop Offset="0.548" Color="Black"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<TextBlock Text="Hello World!" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.Foreground>
<LinearGradientBrush StartPoint="0.472,0.047" EndPoint="0.47,0.942">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.631" Color="Black"/>
<GradientStop Offset="0.635" Color="White"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>
</Border>
Give that a shot, hope this helps.

Categories

Resources