Silverlight: Make all descendants of an element have a margin? - silverlight

Is there a way in Silverlight 4 to dictate that all elements within a StackPanel must have a margin, instead of specifying margin="10,0" on each one?

I'm afraid it's not possible declaratively in XAML with the StackPanel directly. It's the conceptual philosophy in Silverlight/WPF that a panel should not modify properties of its children. So you could implement your own Panel that does so anyway, or you could use an ItemsControl like that:
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Margin="10,0" Content="{Binding Content}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
[...]
</ItemsControl>
An ItemsControl uses a StackPanel by default, you can use its ItemsPanel property to define another Panel as an ItemsPanelTemplate if you wish so.

The way I'd do it is by defining implicit styles in the StackPanel's resources, for each control type that will be used within the StackPanel. To save defining the value repeatedly for each control type, you can create a named base style that targets FrameworkElement and defines the style(s), from which the style for each control type can inherit. An example is below:
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style x:Key="CommonStyle" TargetType="FrameworkElement">
<Setter Property="Margin" Value="10,0" />
</Style>
<Style TargetType="Button" BasedOn="{StaticResource CommonStyle}" />
<Style TargetType="TextBlock" BasedOn="{StaticResource CommonStyle}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource CommonStyle}" />
</StackPanel.Resources>
<Button>Button</Button>
<TextBlock Text="Text" />
<CheckBox>Check Box</CheckBox>
</StackPanel>
Note how each control in the StackPanel will have the margin applied, without needing to define it on each control.
Hope this helps...
Chris Anderson
PS. Blatant self promotion - this is based upon the inheritance trick in my book Pro Business Applications with Silverlight 4 :).

Put your stackpanel within a Border element and set the Border Padding to "10 0"

You can also do this programmatically; your StackPanel has a Children collection. You could use this to iterate through them and set the margin.

Related

XAML : Set Label Margin inside a DataTemplate

I have a DataTemplate directly inside a Resource Dictionary. Inside the template is a label. The margin property isn't being applied how I expected (it has no effect)
<DataTemplate x:Key="HeaderContainerStyle">
<Label Margin="10" Text="{Binding}"/>
</DataTemplate>
And I can't solve the issue with a border as it appears its illegal (?)
<DataTemplate x:Key="HeaderContainerStyle">
<Border Padding="10">
<Label Text="{Binding}"/>
</Border>
</DataTemplate>
I get an error saying cannot resolve symbol Border.
When I try to add it in a ViewCell, application throws an exception:
System.ArgumentException: Value was an invalid value for HeaderTemplate
Parameter name: value
In Xamarin.Forms there is no Border class. Instead you should use Frame class which I think is equivalent for Border in WPF.
Like #Nick said, if you want to use DataTemplates in Xamarin.Forms you need to add ViewCell in DataTemplate and then next next element inside that (for example Grid, StackLayout or Label).
If it comes to Padding, in Xamarin.Forms its only applicable for layout (e.g. Grid, StackLayout) classes. Margin can be specified for view (e.g. Label, Button) and layout classes.
Getting back to your code basing on your HeaderContainerStyle I think you are trying to create style for Label, right?
To do that in Xamarin.Forms you should add new create new Style in ResourceDictionary for specific TargetType.
Example Style for Label class:
<ResourceDictionary>
<Style x:Key="labelRedStyle" TargetType="Label">
<Setter Property="HorizontalOptions"Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="FontSize" Value="15" />
<Setter Property="TextColor" Value="Black" />
<Setter Property="Margin" Value="15,10" />
</Style>
<ResourceDicrionary>
And example usage:
<Grid>
<Label Style="myLabelStyle" />
</Grid>
Let me know if it helped! Waiting for more questions :)
I'm assuming this is Xamarin.Forms and not WPF but if your DataTemplate is used by a ListView it is missing a ViewCell.
<DataTemplate x:Key="HeaderContainerStyle">
<ViewCell>
<Label Margin="10" Text="{Binding}"/>
</ViewCell>
</DataTemplate>
However, if your DataTemplate is used in your own custom control that was created then the ViewCell may not be needed and another issue with that control may be the cause of why Margin is not working.

How to set margin between controls inside of stack panel without duplication?

I can specify the Margin for each stack panel element, but that will be duplication... and in case of change I will need to update all controls...
Is there any way to define that once for the stack panel?
Thank you
(sorry for my bad english)
Xin answers is perfect for what you asked but if you want to set more properties for all the stackPanels I suggest you to create a style:
<Style TargetType="StackPanel" x:Key="CustomStackPanel">
<Setter Property="Margin" Value="10,12,15,20"/>
<Setter Property="Height" Value="50"/>
</Style>
and use it like this:
<StackPanel>
<StackPanel Background="Red" Style="{StaticResource CustomStackPanel}"/>
<StackPanel Background="Green" Style="{StaticResource CustomStackPanel}"/>
<StackPanel Background="Blue" Style="{StaticResource CustomStackPanel}"/>
</StackPanel>
If you remove the x:Key from the style, all StackPanels inside the element that contains the style will use that style. If you declare that style on your app.xaml, all stackPanels on your app will use it.

Access property of element in controltemplate in XAML

I want to use templated ComboBoxItems which consist of an Image and a Label. If I assign the template to a ComboBoxItem, can I somehow set the Source-Property of the Image? The goal is to use the same template for different ComboBoxItems but with different pictures in each Item.
I also thought about binding the Image.Source-Property in the Template, but this fails because the "parent" ComboBoxItem has of course no Source-Property I could bind to.
The code illustrates my problem:
<Style x:Key="ComboBoxPictureItem" TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<StackPanel Orientation="Horizontal">
<Image x:Name="StatusImage" />
<Label x:Name="StatusLabel" Content="Green"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ComboBox>
<ComboBoxItem Style="{StaticResource ResourceKey=ComboBoxPictureItem}"
-> sth. like: StatusImage.Source="PathToMyImage.png"/>
</ComboBox>
Thank you!
You should use template bindings to expose internal properties, e.g. bind the Label's content to the ComboBoxItem's content:
<Label Content="{TemplateBinding Content}"/>
If you now set the Content outside it is transferred to the label, you can do the same for the image, you may run out of properties though so if you want to do things that way you could inherit from ComboBoxItem and create more properties.
Here i do not think you want to mess with control templates really, just use the ItemTemplate to specify how the items look.

Attach xaml style to element without explicitly stating it

I have a problem styling/templating an AccordionItem in the accordion control from the silverlight toolkit. For some reason, the child controls are Horizontally Aligned Left. The only way I can get to fix this is to edit the ExpandableContentControlStyle on the AccordionItem.
The style is located below:
<Style x:Key="ExpandableContentControlStyle1" TargetType="layoutPrimitivesToolkit:ExpandableContentControl">
<Setter.Value>
<ControlTemplate TargetType="layoutPrimitivesToolkit:ExpandableContentControl">
<ContentPresenter x:Name="ContentSite" Cursor="{TemplateBinding Cursor}" Margin="0" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="Stretch" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now my problem is that to have this style being attached to the AccordionItem, I have to set it:
<layoutToolkit:Accordion HorizontalAlignment="Stretch">
<layoutToolkit:AccordionItem Header="Hello" BorderBrush="{x:Null}" ExpandableContentControlStyle="{StaticResource ExpandableContentControlStyle1}"/>
<layoutToolkit:AccordionItem Header="Haha" BorderBrush="{x:Null}"/>
</layoutToolkit:Accordion>
But those AccordionItem will be generated from an ItemSource. What I'd like to do is to have that style be applied to the generated AccordionItem without setting it.
PS. The above problem can become obsolete if I can just find out how to edit the (ContentPresenter x:Name="ContentSite") from the parent Accordion. I cannot edit it from none of the following template properties:
ContentTemplate
ItemContainerStyle
AccordionButtonStyle
ItemsPanel
ItemTemplate
If anyone knows what is going on with that, I'd appreciate the help or you can just help with styling of multiple elements.
I haven't used the Accordion control myself, though typically you set the ItemContainerStyle to the style you want for each item in the list. For instance, if you wanted a specific ListBoxItem style on a ListBox, you set the ItemContainerStyle to the ListBoxItem style you want. I glanced at the source for the Accordion and this seems to hold true for that control as well. Try setting the ItemContainerStyle property of the Accordion to your ExpandableContentControlStyle1.
<layoutToolkit:Accordion
HorizontalAlignment="Stretch"
ItemContainerStyle="{StaticResource ExpandableContentControlStyle1}">
</layoutToolkit:Accordion>
To set the style outside of the control itself, create a style for the Accordion. If you're using Silverlight 4, you can use implicit styles. Put the following style in the <UserControl.Resources> section of your page.
<Style TargetType="layoutToolkit:Accordion">
<Setter Property="ItemContainerStyle" Value="{StaticResource ExpandableContentControlStyle1}"/>
</Style>
Otherwise, with Silverlight 3 you'll have to explicitly give the style a Key and explicitly set the style on the Accordion control.
<Style x:Key="Control_Accordion" TargetType="layoutToolkit:Accordion">
<Setter Property="ItemContainerStyle" Value="{StaticResource ExpandableContentControlStyle1}"/>
</Style>
<layoutToolkit:Accordion
Style="{StaticResource Control_Accordion}"
HorizontalAlignment="Stretch">
</layoutToolkit:Accordion>

WPF ControlTemplate with foreach?

I currently try to create classes for a paint-like WPF application. I have to base classes LineMovement (line from StartPoint to EndPoint) and PathMovement (line going through all points specified in a property Points of type PointCollection). These classes inherit from Control and get their looks through a ControlTemplate.
Now I want to add (what I call) PointMovers to the ControlTemplate. These should be little visual elements residing on each of the points in either of the Movement classes. They should become a kind of grip mechanism to drag the underlying point around.
The problem is of course that I don't know a way to create a variable number of elements in a ControlTemplate. It would be cool if I could do something like this:
<Style x:Key="{x:Type mov:PathMovement}" TargetType="{x:Type mov:PathMovement}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type mov:PathMovement}">
<Grid>
<Polyline Points="{TemplateBinding Points}" />
<!-- interesting part start -->
<foreach loopvariable="Point" in="{TemplateBinding Points}">
<PointMover Point="Point" />
</foreach>
<!-- interesting part end -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is this possible? Do you have another approach in mind that could work?
Thanks in advance!
Use an ItemsControl in conjunction with an ItemTemplate:
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- rendered for each point -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
By the sounds of your use case, you may also want to read up on AdornerLayers.

Resources