How to style child of a UserControl in XAML in Silverlight? - silverlight

I have a UserControl MyParentControl which has another control inside (TreeView). I expose this control as a dep property say TreeView MyChildControl.
Then in XAML which uses MyParentConrol I want to access all the TreeView properties, for example Style.
I want to write something like:
<my:MyParentControl>
<my:MyParentControl.MyChildControl.Style>
<Style />
</my:MyParentControl.MyChildControl.Style>
</my:MyParentControl>
Is there a way to achieve that?

By exposing the DependencyProperty for your inner control you have solved half of the problem - ie you can set individual properties in xaml.
The next step is to have those property setters affect the child control.
There are two options to achieve that.
In your control template, define your child control and use Bindings on each property you want to set.
Define a container element in your parent control template and set it's content to your child whenever the dependency property changes.
Although both of these methods could work, you may find that the solution involving the least amount of code, and the greatest amount of flexibility, is to expose a Style property for your child control and apply that in the control template.
public class ParentControl : Control
{
public Style ChildControlStyle
{
get { return (Style)GetValue(ChildControlStyleProperty); }
set { SetValue(ChildControlStyleProperty, value); }
}
public static readonly DependencyProperty ChildControlStyleProperty =
DependencyProperty.Register("ChildControlStyle",
typeof(Style),
typeof(ParentControl),
new PropertyMetadata(null));
}
<Style TargetType="ParentControl">
<Setter Property="ChildControlStyle">
<Setter.Value>
<Style TargetType="ChildControl">
<!-- setters -->
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ParentControl">
<Grid>
<ChildControl Style="{TemplateBinding ChildControlStyle}" />
<!-- other stuff -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

You would get that effect by writing XAML like this:
<my:MyParentControl>
<my:MyParentControl.Resources>
<Style TargetType="my:MyChildControl">
<Setter Property="Background" Value="Red"/>
</Style>
</my:MyParentControl.Resources>
<my:MyParentControl>
In this example, this XAML creates a MyParentControl in which all the children of type MyChildControl have red backgrounds.

Related

How to set size of CustomControl in Silverlight using TemplateBinding?

I am developing a Silverlight CustomControl, that defines a dependency property named SpinnerSize. Now I want to set the width and height of a Border inside of the default template to the SpinnerSize-property using TemplateBinding:
<Style TargetType="local:MyCustomControl">
<Setter Property="SpinnerSize" Value="12" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyCustomControl">
<Border
Width="{TemplateBinding SpinnerSize}"
Height="{TemplateBinding SpinnerSize}"
Background="Red" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The SpinnerSize reference in the above example is defined as follows:
public static readonly DependencyProperty SpinnerSizeProperty =
DependencyProperty.Register(
"SpinnerSize",
typeof(int),
typeof(MyCustomControl),
new PropertyMetadata(default(int)));
public int SpinnerSize
{
get { return (int)this.GetValue(SpinnerSizeProperty); }
set { this.SetValue(SpinnerSizeProperty, value); }
}
The result is that I don't see the border at all. If I set width and height of the border manually to a value everything works fine.
Is TemplateBinding a valid way to achieve that or do I have to set the width and height manually in the OnApplyTemplate()-method in the control?
Your XAML looks fine, and it is valid to use TemplateBinding like this, so the problem must be in your DependencyProperty.
Height and Width are Doubles. The Binding engine doesn't deal in implicit casts.
Change your DP to that type and it should work fine.

ComboBoxItem, IsEnabled, Binding to table value

I have a dropdownlist control and its ItemsSource is a collection of items which of type T_LookupTable, which is a table in the db, and one of it's columns is 'isEnabled'.
How do I bind the IsEnabled property of the ComboBoxItem in the XAML to this value in the collection?
Further, I have numerous drop-downs in the application which employ this same method, so I would like to somehow make this a global feature if possible, through a static resource, is something like that possible? I found this piece of XAML, which will work, but I want the items to be greyed out in the drop-down, and this method only disables them where you can't click them, but there is no visual indicator which says the item is disabled:
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<ContentPresenter x:Name="ContentPresenter" IsHitTestVisible="{Binding Path=isEnabled}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
I had similar problem with TreeViewItems...
Basically, you have to inherit ComboBox class, override GetContainerForItemOverride method like this:
protected override DependencyObject GetContainerForItemOverride()
{
var result = new ComboBoxItem();
result.SetBinding(Control.IsEnabledProperty, new Binding("IsEnabled"));
return result;
}
It hard codes data binding to IsEnabled property of your data object.

Creating a custom control extending Image

I have a custom control extending Image, and I will put some more data on top of that image. However, when I am trying to style the component, I am getting the error that my Custom Control do not have the property Template Error:
Cannot find the Style Property 'Template' on the type 'MyCustomImage'
How can I style my custom control if Image does not have a Template Property?
Thanks
Edit:
Xaml:
<Style TargetType="{x:Type FieldComponents:MyCustomImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type FieldComponents:MyCustomImage}">
</ControlTemplate>
</Setter.Value>
</Setter>
</style>
Image inherits directly from FrameworkElement, not from Control, so it does not have a Template property. If you want to be able to template your control, you can inherit from Control or UserControl and have your template include an Image.

WPF Setting on a Control Template

General question. I have a ControlTemplate that is reasonably complex. Several TextBoxes etc.
I can't use TemplateBinding to bring all the properties to the surface so that I can set all the styles.
Is there a way for a Style to 'delv' into the controls within a control to set values?
Hope my question is clear without an example.
Thanks
The short answer is no. The ControlTemplate is essentially a black box, at least where XAML is concerned (there are ways to dig down the visual tree in code).
When you say you "can't use TemplateBinding", why not? If you just don't have enough available properties that can be fixed by creating some attached properties for the values you want to pass through. This is assuming you're templating a control that you can't change, otherwise you can just add new dependency properties.
Attached property:
public static class CustomProps
{
public static readonly DependencyProperty MyNewBrushProperty = DependencyProperty.RegisterAttached(
"MyNewBrush",
typeof(Brush),
typeof(CustomProps),
new UIPropertyMetadata(Brushes.Green));
public static Brush GetMyNewBrush(DependencyObject target)
{
return (Brush)target.GetValue(MyNewBrushProperty);
}
public static void SetMyNewBrush(DependencyObject target, Brush value)
{
target.SetValue(MyNewBrushProperty, value);
}
}
And usage in Style and Template:
<Style TargetType="{x:Type Button}">
<Setter Property="local:CustomProps.MyNewBrush" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:CustomProps.MyNewBrush)}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Using this method also still allows overriding values on individual instances.

How to Inherit a Control Template

I working on a WPF project where I've over-ridden the CheckBox control for some special operations. That is working correctly.
My problem is that the ControlTemplate that was applied from the theme (shinyred.xaml from codeplex), is not applied to my over-ridden control. Is there a way to inherit the CheckBox ControlTemplate for use by my new control?
All the samples the I can find are focused on inheriting the style for the CheckBox, but nothing about the ControlTemplate.
No, as you said it is possible to 'inherit' a style by using the BasedOn property, but it's not possible to directly 'inherit' a template. This is understandable though, what would be the semantics of template inheritance? How would the derived template be able to somehow add or change elements in the base template?
With styles it's entirely possible, since you can simply add Setters, Triggers, etc. The only thing that would conceivably be possible with template inheritance is adding Triggers to the base template. However, in that case you'd have to have intimate knowledge of the element names in the base template, and an element name change in the base template could break your derived one. Not to mention an issue with readability, where you refer to a name in your derived template, which is defined somewhere else entirely.
Belated Addition Having said all that, it is possible to resolve your particular problem (although I doubt by now it is still yours, or even a problem). You simply define a style for your control with a setter for the Template property thus:
<Style TargetType="<your type>">
<Setter Property="Template" Value="{StaticResource <existing template resource name>}"/>
</Style>
Keeping in mind what said by #Aviad, the following is a work around:
say you have a Button that define a template that you want to ihnerit, define your CustomButton as Custom Control like this:
public class CustomButton : Button
{
static CustomButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomButton), new FrameworkPropertyMetadata(typeof(CustomButton)));
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text",
typeof(string), typeof(CustomButton), new UIPropertyMetadata(null));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
Then go to your Generic.xaml and define the following:
<Style
x:Key="CustomButtonStyle" TargetType="{x:Type local:CustomButton}">
<Setter Property="FontSize" Value="18" /> <!--Override the font size -->
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomButton}">
<Button Style="{StaticResource ButtonStyleBase}"
Height="{TemplateBinding Height}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:CustomButton}}, Path=Command}"
CommandParameter="{Binding}"
Width="{TemplateBinding Width}">
<Grid>
<StackPanel>
<Image Source="Image/icon.jpg" />
<TextBlock Text="{TemplateBinding Text}"></TextBlock>
</StackPanel>
</Grid>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Note that the button we want to inherit the template is wrapped inside my new template, and the style is set to the existing button. go the same way with the checkbox and organize the checkbox and label for instance vertically inside the new ControlTemplate of the CustomCheckBox

Resources