WPF Toolbar - Custom Style - wpf

I want to change the standard style of a wpf toolbar. I use the following Style in the Control Resources, which works fine:
<Style x:Key="{x:Type ToolBar}" TargetType="{x:Type ToolBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolBar}">
<Border>
<DockPanel VerticalAlignment="Stretch" Height="38">
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
However, if i add items to a toolbar, these items are not shown:
<ToolBar x:Name="myToolbar">
<Label>test</Label>
</ToolBar>
I do NOT want to add the items in the template, but in a specific toolbar which uses that template.
Can anyone give me a hint?

The problem is that you replaced the toolbar's control template with your own. But you haven't specified in that template where items should be shown. Typically you would do it either by adding an ItemsPresenter:
<ControlTemplate TargetType="{x:Type ToolBar}">
<Border>
<DockPanel VerticalAlignment="Stretch" Height="38">
<ItemsPresenter/>
</DockPanel>
</Border>
</ControlTemplate>
Or by setting IsItemsHost="True" on a panel inside the template:
<ControlTemplate TargetType="{x:Type ToolBar}">
<Border>
<DockPanel IsItemsHost="True" VerticalAlignment="Stretch" Height="38">
</DockPanel>
</Border>
</ControlTemplate>
But, if you try to replace the items panel for the ToolBar (as in my second example), it will not work, because ToolBar expects the ToolBarPanel to be the items panel.

A template defines how a control is rendered, for some controls everything is within the template for others the control expects to find named elements within the template which it will manipulate. If you look at the ToolBar template you can see that the toolbar expects to find an element named PART_ToolBarPanel and an element named PART_ToolBarOverflowPanel within the template:
http://msdn.microsoft.com/en-us/library/aa970772.aspx
For example, it needs to locate the element named PART_ToolBarPanel in order to add the items to the toolbar.
If you want to add new elements to the toolbar template, typically you would start by copying the existing template, then start adding / removing element.

Related

Ensuring AdornmentDecorator within a ContentPresenter, but without a ControlTemplate

I've searched around quite a bit and can't seem to crack this nut.
I've got an app with a main view that changes dynamically, and to do this I use content presenter with a binding to a control:
<ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
<StackPanel Margin="20,20,20,500">
<ContentPresenter Content="{Binding MainControl}"/>
</StackPanel>
</ScrollViewer>
Then I change the MainControl at runtime in my view model. The problem is that the controls getting bound don't reliably display their error templates... I suspect it is for the reasons discussed here:
Validation ErrorTemplate not showing on data errors
But the fix for this problem doesn't seem to work for me because I'm not using a control template around my content presenter. When I wrap an AdornmentDecorator tag around my content presenter, it doesn't seem to fix the problem. It DOES work if I put an AdornmentDecorator inside each control I load into the contentpresenter (as the root element), but I'd like to avoid this repetition if possible.
Any insights?
UPDATE
I tried this approach suggested by Dennis, but to no avail. The control binds okay, but it works no better than the current approach (also shown commented below). Note: I tried it both with the AdornerDecorator as a singleton element the way Dennis has it, and surrounding the ContentPresenter, as shown below. Neither show any difference - the adorners around my controls all disappear when the MainControl binding is changed.
<UserControl.Resources>
<Style x:Key="MainContentControl" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Grid>
<AdornerDecorator>
<ContentPresenter Content="{Binding MainControl}"/>
</AdornerDecorator>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
.....
<ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
<StackPanel Margin="20,20,20,500" >
<ContentControl Style="{StaticResource MainContentControl}"/>
</StackPanel>
</ScrollViewer>
<!-- THE BELOW WORKS IF I SURROUND EACH BOUND CONTROL WITH adornerdecorator -->
<ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
<StackPanel Margin="20,20,20,500">
<ContentPresenter Content="{Binding MainControl}"/>
</StackPanel>
</ScrollViewer>
-->
Instead of using a ContentPresenter directly, I would instead use a ContentControl. A ContentControl is the base class for controls that contain other elements and have a Content property, e.g. Button.
Then you can override the template to have an AdornerDecorator next to the ContentControl. This is different to what you previously tried as now the ContentPresenter is part of the same visual tree as the Adorner.
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Edit: Forgot that the AdornerDecorator needs to wrap the container, not just sit side-by-side.

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.

ItemsControl, ItemsPanel and ItemsPresenter (Silverlight, XAML)

I'm utterly confused by these 3 terms, when to use which? What's the relationship and they are children of which controls?
Is it correct to say this is the tree:
ItemsControl > ItemsPresenter > ItemsPanel
ItemsControl is conceptually a control that houses items. Try to simply think of this control as a holder for zero or more objects.
ItemsPresenter is a bit tougher to explain, but this is part of the ItemsControl template that will define where the items are placed within it. Your ItemsControl's template can be anything you like, say a Grid with some pretty pictures around it, inside this template, you would place the ItemsPresenter where ever you want your items to be, say right in the middle of your grid. (this example is taken from msdn and simplified for ease of reading)
<Style TargetType="HeaderedItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
<Grid>
<Rectangle Stroke="Black" Fill="Red"/>
<ItemsPresenter Margin="2,0,0,0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The ItemsPanel is the panel (or container) that controls the layout of the items in your ItemsControl. So if you want your items that you have added to your ItemsControl to display in a horizotal way, then yor items panel could simply be a StackPanel with its Orientation property set to Horizontal.
This all make sense?
I think that this pretty much explains how the things are done by Silverlight:
ItemsPanelTemplate Class:
Specifies the panel that the ItemsPresenter creates for the layout of the items of an ItemsControl.
ItemsPanelTemplate Class
<Style TargetType="local:myItemsControl">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:myItemsControl">
....
<ItemsPresenter />
....
Basically, the ItemPresenter (specified in the Template) will be replaced with whatever is specified in the ItemsPanelTemplate.
So, the Template can be extended to include a header and all child will be placed under this header:
<Grid> <TextBlock Text="Header"/> <ItemsPresenter /> </Grid>

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>

ItemContainerStyle in Custom Control Derived From ListBox

Please bear with me Silverlight Designer Gurus, this is compicated (to me).
I'm creating a custom control which derives form the Silverlight 3.0 ListBox. In an effort not to show tons of code (initially), let me describe the setup.
I have a class library containing a class for my control logic. Then I have a Themes/generic.xaml that holds the styling details. In generic.xaml, I have a style that defines the default layout and look for the ListBox where I'm setting a values for the Template, ItemsPanel and ItemTemplate.
In my test app, I add my control on to MainPage.xaml and run it and it works great. I dynamically bind data to my control and that works fine.
Now I want to set the ItemContainerStyle for my derived control. If I create a style in the MainPage.xaml file and set the ItemContainerStyle property to that control as in:
<dti:myControl x:Name="MyControl1" ItemContainerStyle="{StaticResource MyListBoxItem}"
Height="500"
Width="200"
Margin="10"
Background="AliceBlue"
/>
It works as expected.
However, I'd like to do this in the class library or, more specifically, in generic.xaml. I tried to this Setter to my current Style:
<Setter Property="ItemContainerStyle">
<Setter.Value>
<ControlTemplate>
<Grid Background="Red" Margin="3">
<ContentPresenter x:Name="contentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="Stretch" Margin="3"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
And it fails miserably with:
"System.ArgumentException: 'System.Windows.Controls.ControlTemplate' is not a valid value for property 'ItemContainerStyle'."
Note: This is not my actual style I'd like to use for ItemContainerStyle. I'm actually looking to plug in some VSM here for the various selected/unselected states of the a ListBoxItem (for a dynamically bound control).
So, to the question is how do I apply the ItemContainterStyle to my custom control when it's defined using generic.xaml? I do not want that property set when I actually use the control later on.
Thanks,
Beaudetious
You missed to put Style tag inside your Setter.Value. ItemContainerstyle explects a Style to ListBoxItem(Unless you subclassed ListBoxItem to your own derived version.)
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType=”{x:Type ListBoxItem}“ >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="Red" Margin="3">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="Stretch" Margin="3"/>
</Grid>
</ControlTemplate>
<Setter.Value>
</Style>
</Setter.Value>

Resources