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

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.

Related

Binding ContentPresenter.Content to TemplatedParent (WPF/Silverlight)

Basically, I would like to overlay, for example: TextBlock over Button, by using ControlTemplate (applied to this Button), but I don't want to get rid of default template of it.
Example:
<Grid Grid.Row="1" Grid.ColumnSpan="2">
<Grid.Resources>
<Style x:Key="myStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter />
<TextBlock Text="textBlock"
Margin="10" Foreground="Red"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Button Style="{StaticResource myStyle}" Content="button1"></Button>
</Grid>
and it gives Button stripped of it's default template:
Rather, I would like to receive something like this:
Is it possible by using ControlTemplate? I was trying to bind TemplatedParent to ContentPresenter.Content like here:
<ContentPresenter Content="{Binding
RelativeSource={RelativeSource Mode=TemplatedParent},
Path=.,
Mode=TwoWay}"/>
or other combinations, but I couldn't make it work.
Edit:
Because I would like to be able to apply this TextBlock not only to a button (it was just an example) but to any Control, I don't want do it by copying default style (to the resources or somewhere), for every Control.
Also, I would prefer not to create UserControl, because I would like to keep xaml clean as much as possible (I mean with system Controls) - and just to turn on/off the overlaying TextBlock by using a ControlTemplate.
You could add the default style on the button and modify it to add your TextBlock. The second option, my preference, is to create a new UserControl that will contain the Button and the TextBlock with IsHitTestVisible=False. You can then add dependency properties to be able to bind to the button and the text block.

sort of special accordion like control

I have put an example link in here:
http://activeden.net/item/xml-horizontal-vertical-accordion-banner-rotator/full_screen_preview/127714?ref=premiumtemplates
I try to achieve something similar (but far more basic) with WPF.
Not the flying text stuff, only the basic navigation idea.
I tried to build it with some expander controls and a stackpanel.
What I came up with is this:
<ItemsControl Grid.Row="1" IsTabStop="False" ItemsSource="{Binding Path=tabs,Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I use MVVM, so there is also a template which is applied:
<DataTemplate DataType="{x:Type vm:TabulatorViewModel}">
<Expander HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ExpandDirection="{Binding .direction,Mode=OneWay}" IsExpanded="{Binding .isExpanded,Mode=TwoWay}" Header="{Binding .header,Mode=OneWay}" >
<Expander.Style>
<Style TargetType="{x:Type Control}">
<Setter Property="Template" Value="{StaticResource HorizontalExpanderRight}" />
<Style.Triggers>
<DataTrigger Binding="{Binding .direction}" Value="Left">
<Setter Property="Template" Value="{StaticResource HorizontalExpanderLeft}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<StackPanel>
<Label Content="{Binding .seitenInhalt.Header,Mode=OneWay}"></Label>
<TextBox Text="{Binding .seitenInhalt.Inhalt,Mode=OneWay}"></TextBox>
<Button Content="zurück" Command="{Binding .seitenInhalt.MovePreviousCommand}" />
<Button Content="vor" Command="{Binding .seitenInhalt.MoveNextCommand}"/>
</StackPanel>
</Expander>
</DataTemplate>
So, this is working, at least kind of.
two screenshots from my current project to explain the issues:
Could not post picture because of reputation points.
All Items together should use the complete width of the stackpanel, not like in the picture. Could not post picture because of reputation points.
All items should use the complete width, but the one expanded item should have a bigger width then the rest. As on the picture, but the collapsed items should use the remaining space, each by the same amount filling the gap)
Any help would be great, I hope it is possible to understand my goal / issues.
I think what you want to use is a UniformGridPanel or WrapPanel, which will use the full width available, rather than a StackPanel which is made to use the minimum width possible. The panel overview is here.
You'll probably want to use a Grid with the Height/Width of the Columns/Rows set to * if the item is Expanded, or Auto if not.
Also, if you're using a Grid in an ItemsControl, you need to set the Grid.Row/Grid.Column, and Width/Height properties on the ContentPresenter, not the ItemTemplate since the ItemTemplate in a ItemsControl is always wrapped in a ContentPresenter.

How can I style a custom control based on if any of its children have focus?

We have a custom canvas which has specialized nodes that behave a lot like a standard MDI application's windows. The desired behavior is that if any of the child controls of the "window" have the focus, then that "window" is said to be active.
Now the IsFocused property doesn't seem to cascade, meaning if a child control has the focus, it's container is not also set to 'focused' so we can't use that. For the same reason, we can't set the IsFocused property on the container as I believe that would steal it from the child.
My only thought is to create a new DP called HasChildWithFocus or something like that, then in the code-behind, listen for the bubbled events and set that flag. Not sure that's the best way to go. (We may implement that as a combination attached property/attached behavior kinda thing.)
But of course it would be much better if we could simply ask a control 'Hey... do you or any of your children have the focus?'
So can you?
You can use UIElement.IsKeyboardFocusWithin directly like this:
<Grid>
<Grid.Resources>
<Style x:Key="panelStyle" TargetType="Border">
<Setter Property="BorderBrush" Value="PaleGoldenrod"/>
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="BorderBrush" Value="PaleGreen"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<UniformGrid Columns="2">
<Border BorderThickness="10" Style="{StaticResource panelStyle}">
<StackPanel>
<TextBox Text="TextBox1"/>
<TextBox Text="TextBox2"/>
</StackPanel>
</Border>
<Border BorderThickness="10" Style="{StaticResource panelStyle}">
<StackPanel>
<TextBox Text="TextBox3"/>
<TextBox Text="TextBox4"/>
</StackPanel>
</Border>
</UniformGrid>
</Grid>
In this example the border that contains the element with the keyboard focus is styled with a different border brush.

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

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.

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>

Resources