WPF, dynamic Color Fill Rectangle - wpf

I try to create a ControlTemplate for my Label like this :
<Style TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Grid x:Name="LayoutRoot" Background="White">
<Rectangle Height="30" HorizontalAlignment="Left" Margin="10"
Stroke="transparent"
VerticalAlignment="Top" Width="3"
Fill="#FF259FED" />
<ContentPresenter HorizontalAlignment="Left" Margin="17,0,0,0" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#7A7E81" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
I want to fill color of rectangle when i create my control, like this for example :
<Label Content="Prénom" VerticalAlignment="Top" CouleurRectangle="#FF259FED" />
So, how can I change Property "Fill" in my controlTemplate to set dynamicly color of rectangle when i create control ?
thank's a lot.
Edit : this is the solution , i create a new class who inherit from Label like this :
Public Class LblTitreChamp
Inherits Label
Public Shared ReadOnly CouleurProperty As DependencyProperty =
DependencyProperty.Register("CouleurRectangle", GetType(SolidColorBrush), GetType(LblTitreChamp))
''' <summary>Propriété pour insérer une couleur au début du Label</summary>
Public Property CouleurRectangle As SolidColorBrush
Get
Return GetValue(CouleurProperty)
End Get
Set(ByVal value As SolidColorBrush)
SetValue(CouleurProperty, value)
End Set
End Property
End Class
then, in my COntrolTemplate :
<Style TargetType="{x:Type local:LblTitreChamp}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:LblTitreChamp}">
<Grid x:Name="LayoutRoot" Background="White">
<Rectangle Height="30" HorizontalAlignment="Left" Margin="10"
Stroke="transparent"
VerticalAlignment="Top" Width="3"
Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Label}}, Path=CouleurRectangle}"/>
<ContentPresenter HorizontalAlignment="Left" Margin="17,0,0,0" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#7A7E81" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
and finally, to creat a new label :
<my:LblTitreChamp Content="ID" VerticalAlignment="Top" CouleurRectangle="Black" />
thank's a lot for you :)

hi set Fill={TemplateBinding CouleurRectangle} .Hope this will help. And i Expect that you have created a custom Label class That inherit from Label and has DependencyProperty CouleurRectangle.

Since your label is not a CustomControl, then you cannot dynamically make a property on that so the best possible way is to use the background property of label
...
<Rectangle Height="30" ...
Fill="{TemplateBinding Background}" />
...
Else create a CustomControl inheriting the Label and make a new dependency property and also define a XAML template style for it.

Related

WPF - How do I get the value from the parent element?

Hi i am trying to pass from Button Content to ControlTemplate -> Label Content
How can i do this?
I am just starting to learn xaml and faced such a problem, I would be very grateful for any help.
Code:
<Style x:Key="CloseBtn" TargetType="Button">
<Setter Property="Content" Value="Flex"/> <!---From here --->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Label Name="Border" Focusable="False" Background="#00ff0000" Foreground="#A770FA"
Content="" <--- Over here --->
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>```
Use relative source in your binding to bind to properties on a parent control, in this case, it could be either :
<Label Name="Border" Focusable="False" Background="#00ff0000" Foreground="#A770FA"
Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}},Path=Content}"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
OR
<Label Name="Border" Focusable="False" Background="#00ff0000" Foreground="#A770FA"
Content="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
Relative source also allows you to bind to properties on the same control , ancestors upto a certain level, etc. Please refer to the documentation : https://learn.microsoft.com/en-us/dotnet/api/system.windows.data.relativesource?view=net-5.0

Bind TextBlock.Text to specific item-property in collection where value matches another binding

Trying to stay on the MVVM road, I keep struggling with the following task for hours:
I want to show the String-value of a specific Item (in a TextBlock), which is part of the UserCollection (ObservableCollection<Tuple<int, string>>). The selection should take place via the Int-property of the item in the Collection, matching the bound IdCreatedByUser-Property in MyOrder.
To make things more clear:
An UserCollection that holds an ID (int) and NAME (string):
public ObservableCollection<Tuple<int, string>> UserCollection;
A MyOrder-Property holding an Instance of the Orders-Class:
public Order MyOrder;
Here an example of the Orders-class.
public class Order: INotifyPropertyChanged
{
public string Comment;
public int IdCreatedByUser;
public bool IsComplete;
}
Please note that this is just an example for the properties..knowing that get,set are missing here..
The only solution I came up with is to hijack a Combox like this:
<ComboBox ItemsSource="{Binding UserCollection}"
DisplayMemberPath="Item2"
SelectedValue="{Binding MyOrder.IdCreatedByUser}"
SelectedValuePath="Item1">
<ComboBox.Template>
<ControlTemplate>
<TextBlock Text="{Binding SelectedItem.Item2,RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</ControlTemplate>
</ComboBox.Template>
</ComboBox>
The fact that I can use ItemsSource, SelectedValue and SelectedValuePath makes it possible for me to select and show the desired Item. Any solutions for the use of TextBlocks with this one?
I was also thinking about a converter or extra property..but maybe you can show me a way to design this in a better way..
Thanks!
This essentially makes your specialized ComboBox easily reusable. Stuff like FontWeight will be inherited by the ContentPresenter.
<Style x:Key="CollectionLookupComboBox" TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
<!--
Default to readonly, but you can override that for particular instances
if that's useful somewhere.
-->
<Setter Property="IsReadOnly" Value="True" />
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border
x:Name="OuterBorder"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Transparent"
>
<!--
The margin here keeps the text in the same spot when I toggle IsReadOnly,
with the default theme I have. May need to fiddle with that to get it to
look right for you.
-->
<ContentPresenter
Margin="3,2,2,0"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
VerticalAlignment="Stretch"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Example -- this is overkill; you don't need an ItemTemplate or boldface, but it demonstrates how all the usual ComboBox stuff is supported:
<StackPanel
Orientation="Vertical"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
>
<CheckBox
x:Name="ReadOnlyCheckBox"
IsChecked="True"
Margin="1"
Content="Read-Only"
/>
<ComboBox
Margin="1"
Style="{StaticResource CollectionLookupComboBox}"
IsReadOnly="{Binding IsChecked, ElementName=ReadOnlyCheckBox}"
MinWidth="80"
SelectedIndex="0"
FontWeight="Bold"
Foreground="Green"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DeepSkyBlue" BorderThickness="2" CornerRadius="4">
<Label Content="{Binding}" />
</Border>
</DataTemplate>
</ComboBox.ItemTemplate>
<sys:String>First Item</sys:String>
<sys:String>Second Item</sys:String>
</ComboBox>
</StackPanel>

Canvas with Children as a Style

Sorry if this is a dense question, but I'm looking to see if there is a way to have a style resource of Canvas in App.xaml and also have children on that Canvas and just refer to it in the Style of another canvas. The resource I envision would be something like:
<Style x:Key="Background1" TargetType="Canvas">
<Setter Property="Width" Value="500"/>
<Setter Property="Height" Value="600" />
<Setter Property="Background" Value="Red"/>
<Setter Property="Children">
<Setter.Value>
<Rectangle Canvas.Top="20" Canvas.Left="20" Width="100" Height="100" Fill="Yellow"></Rectangle>
</Setter.Value>
</Setter>
</Style>
And then calling it would be as simple as:
<Canvas Style="{StaticResource Background1}" x:Name="CanvasRoot" >
<Rectangle x:Name="PageRectangle" Canvas.Left="114" Canvas.Top="84" Height="378" Width="210" Stroke="#92D050" Fill="#C0504D" />
</Canvas>
Any thoughts on if something like this can be done. What I've done doesn't work because there is no "Children" property on Canvas.
So you want to add a child to a Canvas via a Style? I'm afraid this is simply not possible. Styles allows you to set the values of an elements dependency properties, such as Height, Background, Stroke etc ... You can also use them to set attached properties. However, the Children property you are trying to set is not a dependency property, it is the collection of children elements that describe the children of your canvas in the visual tree.
The only way to add new elements t the visual tree using styles is to add them to some controls template. Unfortunately you canot template panels (Canvas, Grid, StackPanel). You could use a ContentControl and add your rectangle as part of its template.
A ContentControl is a lookless container of a single child. See the template described here:
http://msdn.microsoft.com/en-us/library/dd334411%28VS.95%29.aspx
Here it is, templates to add a rectangle. I am not sure what layout you are trying to achieve, but it should give you the general idea
<Style TargetType="ContentControl" x:Key="myContentControl">
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Canvas>
<Rectangle Canvas.Top="20" Canvas.Left="20" Width="100" Height="100" Fill="Yellow"></Rectangle>
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
<ContentControl Style={StaticResource myContentControl}>
<Canvas x:Name="CanvasRoot" >
<Rectangle x:Name="PageRectangle" Canvas.Left="114" Canvas.Top="84" Height="378" Width="210" Stroke="#92D050" Fill="#C0504D" />
</Canvas>
</ContentControl>

WPF Image Command Binding

I'm putting a WPF application together in which I have an image control which I want to bind a custom command object to from my view model that will execute when the image is clicked. I have exposed the command object from my view model and just need to bind it to the image control.
Is it possible to bind this command object to an image control? If so any advice would be appreciated.
Here's yet another solution I personally love to use most of the time if I want an image with command without enclosing it in another control.
<Image Source="Images/tick.png" Cursor="Hand" Tooltip="Applies filter">
<Image.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding ApplyFilter, Mode=OneTime}" />
</Image.InputBindings>
</Image>
I set its properties Hand and Tooltip so that it's more clear that it's an action and not a static image.
You need to put the image in a button, and bind the button to the command:
<Button Command="{Binding MyCommand}">
<Image Source="myImage.png" />
</Button>
If you don't want the standard button chrome, just change the template of the button with something like that:
<ControlTemplate x:Key="tplFlatButton" TargetType="{x:Type Button}">
<Border Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
TextElement.Foreground="{TemplateBinding Foreground}"
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontStretch="{TemplateBinding FontStretch}"
TextElement.FontWeight="{TemplateBinding FontWeight}"/>
</Border>
</ControlTemplate>
Note that you will also need to change other properties to override the default button style, otherwise the template above will use the default button background and border:
<Style x:Key="stlFlatButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template" Value="{StaticResource tplFlatButton}" />
</Style>
It can be simpler to avoid using a button and use a Hyperlink instead:
<TextBlock DockPanel.Dock="Top">
<Hyperlink Command="{Binding SomeCommand}">
<Image Source="image.png" />
</Hyperlink>
</TextBlock>
Note that this will render the hyperlink with the default text decoration, so you'll want to add a style that removes that - putting this in the resource dictionary of the containing element will do the trick:
<Style x:Key={x:Type Hyperlink}" TargetType="Hyperlink">
<Setter Property="TextDecorations"
Value="{x:Null}" />
</Style>
Simplified version of answer from #Robert Rossney:
<TextBlock>
<Hyperlink Command="{Binding SomeCommand}" TextDecorations="{x:Null}">
<Image Source="{StaticResource image.png}" Width="16" />
</Hyperlink>
</TextBlock>
The best way to include an image is to use a {StaticResource x}, see WPF image resources
reset control template of the button and use image in control template..
<Button Width="100" Height="100" Command="{Binding SampleCommand}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Image Stretch="Uniform" Source="Images/tick.png"></Image>
</ControlTemplate>
</Button.Template>
</Button>

Silverlight: Binding a custom control to an arbitrary object

I am planning on writing a hierarchical organizational control, similar to an org chart. Several org chart implementations are out there, but not quite fit what I have in mind.
Binding fields in a DataTemplate to a custom object does not seem to work.
I started with a generic, custom control, i.e.
public class NodeBodyBlock : ContentControl
{
public NodeBodyBlock()
{
this.DefaultStyleKey = typeof(NodeBodyBlock);
}
}
It has a simple style in generic.xaml:
<Style TargetType="org:NodeBodyBlock">
<Setter Property="Width" Value="200" />
<Setter Property="Height" Value="100" />
<Setter Property="Background" Value="Lavender" />
<Setter Property="FontSize" Value="11" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="org:NodeBodyBlock">
<Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
Background="{TemplateBinding Background}" CornerRadius="4" BorderBrush="Black" BorderThickness="1" >
<Grid>
<VisualStateManager/> ... clipped for brevity
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My plan now is to be able to use this common definition as a base definition of sorts, with customized version of it used to display different types of content.
A simple example would be to use this on a user control with the following style:
<Style TargetType="org:NodeBodyBlock" x:Key="TOCNode2">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=NodeTitle}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
and an instance defined as
<org:NodeBodyBlock Style="{StaticResource TOCNode2}" x:Name="stTest"
DataContext="{StaticResource DummyData}" />
The DummyData is defined as
<toc:Node NodeNumber="mynum" NodeStatus="A"
NodeTitle="INLine Node Title!"
x:Key="DummyData"/>
With a simple C# class behind it, where each of the fields is a public property.
When running the app, the Dummy Data values simply do not show up in the GUI. A trivial test such as
<TextBlock Text="{Binding NodeTitle}" DataContext="{StaticResource DummyData}"/>
works just fine.
Any ideas around where I am missing the plot?
Update: Binding to the datacontext in the definition in generic.xaml works fine, but any binding in the ContentPresenter is lost.
Your control template is missing a binding on the ContentPresenter, it should look like this:-
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
I just ended up using this example as a base:
http://10rem.net/blog/2010/02/05/creating-customized-usercontrols-deriving-from-contentcontrol-in-wpf-4
Not quite sure what I missed, but the example works.

Resources