Silverlight - specify stackpanel contents of a user control in the parent - silverlight

I created a user control called 'RibbonTabX' which contains a stackpanel named 'spMain'. What I'd like to do, is when I declare an instance of my 'RibbonTabX' in xaml, within that same xaml I'd like to specify controls which will be inside the child stackPanel 'spMain'. Here is the code which will make what I'm trying to do much clearer:
<ribbon:RibbonTabX strHeaderText="Testing 123...">
<ribbon:RibbonTabX.spMain>
<sdk:Label Content="Hello" />
<sdk:Label Content="World" />
</ribbon:RibbonTabX.spMain>
</ribbon:RibbonTabX>
In the parent of RibbonTabX, I want to specify child contents of the stackpanel within my user control 'RibbonTabX'. Just like you can do with a 'TabItem' control. Any ideas how I can do this?
Thanks!

You need to create a custom content control, not a user control.
Start with this article
It is more complex than a user control as you have to hand-craft a generic template for it, but they are more versatile.

You want to use a ContentControl. Rather than specify that those controls go in the stack panel you probably should just place the Content in the stack panel. Have your RibbonTabX derive from ContentControl rather than UserControl, then where it is appropriate put the <ContentPresenter /> then the user of the ribbon can put whatever into it.
<ribbon:RibbonTabX strHeaderText="Testing 123...">
<StackPanel>
<sdk:Label Content="Hello" />
<sdk:Label Content="World" />
</StackPanel>
</ribbon:RibbonTabX>
Here is the most basic ContentControl possible:
<ContentControl x:Class="SilverlightControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="Orange">
<ContentPresenter />
</Grid>
</ContentControl>

Related

Can you repeat a block of controls inside a Ribbon?

My app has a number of ribbon tabs and there is a certain group of ribbon controls that needs to be repeated on a few of these tabs. These are not dynamic content, just static elements that are used repeatedly.
I could just repeat the XAML for those controls in 2-3 places but it seemed that there should be a cleaner way to do this...
I have tried to create a UserControl to house the repeated elements, but with mixed success. I've pasted below what I've done. This does work in the sense that the contents of the UserControl are shown within each RibbonTab; but here are the problems:
Without the UniformGrid (or any other 'standard' panel like WrapPanel ) it is not possible to include multiple Ribbon controls in the UserControl. But because this panel controls the layout these controls don't correctly participate in the usual Ribbon layout rules (such as when your window is resized & the ribbon control sizes can change.)
I have to wrap the UserControl inside a RibbonGroup in each place it is used. Initially I intended to have the RibbonGroup be the main panel inside the UserControl, but this did not layout correctly - all the subsidiary controls were rendered almost entirely below the lower ribbon border?
I have the sense that some type of templating solution may be a better choice. I have read however that some of the Ribbon controls were designed not following typical WPF standards for how templates are used and that adds a lot of uncertainty.
Note that while I'd probably prefer a XAML-only approach, if some code behind neatly gets this done I think that would be fine.
UserControl:
<UserControl x:Class="ribbon1.SampleUC" ...>
<UniformGrid Columns="2" Rows="1">
<RibbonButton
Label="Zoom In"
SmallImageSource="..."
/>
<RibbonButton
Label="Zoom Out"
SmallImageSource="..."
/>
</UniformGrid>
</UserControl>
Main ribbon:
<Ribbon>
...
<RibbonTab Header="Tab1">
...
<RibbonGroup>
<l:SampleUC/>
</RibbonGroup>
</RibbonTab>
<RibbonTab Header="Tab2">
...
<RibbonGroup>
<l:SampleUC/>
</RibbonGroup>
</RibbonTab>
...
</Ribbon>
Replace the UserControl Tag in SampleUC.xaml with RibbonGroup and change the parent class in the code behind file.
<RibbonGroup x:Class=".SampleUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UniformGrid Columns="2" Rows="1">
<RibbonButton Label="Zoom In" />
<RibbonButton Label="Zoom Out" />
</UniformGrid>
public partial class SampleUC : RibbonGroup
{
public SampleUC()
{
InitializeComponent();
}
}
Now you can use it like that
<Ribbon>
<RibbonTab Header="Tab1">
<l:SampleUC/>
</RibbonTab>
</Ribbon>

Using a user control as a context menu in WPF

I've created a WPF user control that contains some grids, buttons, and sliders. I'd like to use this control as (or in place of) a context menu in my main application window. When a user right-clicks the mouse button, I'd like my user control to be displayed, rather than a normal looking context menu with standard menu items.
What's the best approach to take in displaying a user defined WPF control in place of a context menu?
You could define the ControlTemplate of a ContextMenu however you want. Try this:
<Window ... xmlns:local="clr-namespace:WpfApplication1">
<Grid Background="Transparent">
<StackPanel.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate TargetType="ContextMenu">
<local:UserControl1 />
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</StackPanel.ContextMenu>
Just add the control to the ContextMenu. For example:
<Window>
<Window.ContextMenu>
<ContextMenu>
<local:YourUserControl />
</ContextMenu>
</Window.ContextMenu>
</Window>

How to expose ItemTemplate and ContentTemplate from a UserControl

I have written a Well control, similar to the Visual Studio editor tabs so that a user can have multiple documents open and can see one or more at a time. It is derived from a UserControl and exposes an ObservableCollection of OpenDocuments that binds to the ViewModel. If I were to implement this as a simple TabControl, then this would be how it would look:
<TabControl
Grid.Row="1"
Grid.Column="1"
ItemsSource="{Binding OpenDocuments}"
SelectedItem="{Binding SelectedTab, Mode=TwoWay}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<vw:DocumentView />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This gives me Name in the tabitem header and the DocumentView (another user control in the Content area).
My control has a ContentTemplate but it is of course representing the whole of the control so all I get to see is the DocumentView. My control doesn't have an ItemTemplate.
How do I expose an ItemTemplate and ContentTemplate?
Andrew
EDIT -------------------------------------------------------------------------
Thanks for the replies. It looks like this:
A user can have one or more document wells holding one or more tabs. All the consumer has access to is the list of visible tabs and the currently selected tabitem.
Notice that the tabs are all empty! I don't understand how to specify the ContentTemplate for the <vw:DocumentView> in the same way as the TabControl example above.
Andrew
I am a little confused on exactly what your control looks like but here is what I think you are after.
If your control can inherit from ItemsControl you will get the ItemTemplate property already defined for you. All you have to do in your control template is to Template bind the ItemsControl property to the correct place in the template.
The same applies for the ContentTemplate. If you have the a ContentTemplate property already defined for you control you just need to Template Bind it to the correct place in the control.
It would look something like this
Control Consumer
<MyControlNamespace:MyControl ContentTemplate="{StaticResource MyContentTemplate}" ItemTemplate="{StaticResource MyItemTemplate}" />
Implementation of "MyControl" from above (totally pseudo code)
<MyControl>
<ItemsPresenter ItemTemplate="{TemplateBinding ItemTemplate}" />
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" />
</MyControl>
Again, my example doesn't fully make sense but I am not sure what your control looks like and not entirely sure what you are asking, but hopefully this helps.

How to determine if a custom control is in a Toolbar?

i have created a UserControl to make an ImageButton:
<Button x:Class="myimagebutton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:imagebutton">
<Grid x:Name="grdButton">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
x:Name="btnImage"
HorizontalAlignment="Left"
VerticalAlignment="Center">
</Image>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Text="{Binding Text}"
VerticalAlignment="Center"
Margin="2 0 2 0" />
</Grid>
</Button>
now i want to apply the default Toolbar Button Style to my Button if this Button is in a Toolbar. I have read this article link text and put this
If Me.Style Is Nothing AndAlso TypeOf Me.Parent Is ToolBar Then
Me.Style = DirectCast(FindResource(ToolBar.ButtonStyleKey), Style)
End If
in my Code behind.
After that as a test I put my Button both in a Toolbar and another out of the Toolbar to test it. But the Button always get the default style, not the style I am trying to set.
After debugging i find out that Me.Parent is always Nothing. So now is my question: how i get the information that my button is in a toolbar or not?
I'm having some difficulty understanding exactly what you are describing but after reading it through a few times I think I understand.
Am I right so far?
If so, you are wondering then why your button has an image
A few pointers about your description that threw me off and is probably the reason why you haven't seen anybody else post an answer for your question thus far.
i replaced the the UserControl Item with a Button
Essentially what you have done is created new control that likely inherits from Button. You might have started off with a UserControl but in order to replace the root item in XAML you would also have to make sure your type myimagebutton inherits from Button as well. This is just how XAML works and learning how to explain it this way will help people understand what you are doing.
Normally inheriting from Button is not how developers override the visual style of a button in WPF mainly because WPF doesn't support the concept of what is sometimes referred to as visual inheritance and also there are other suitable methods that can be used to solve the problem in a different way. Instead inheritance is mainly reserved for when behavioral modifications or additions need to be made to an existing control class. This being said there are ways to simulate visual inheritance through the use of content controls that work similar to content pages and master pages in ASP.NET but I think this is a bit outside of the scope of your example. Also if you are to pursue the inheritance model you will need to make sure that in your code behind that you are setting the correct default style in the static constructor so posting your code behind for your button would help too.
I believe the reason why your example isn't working is because the ToolBar specifically looks at the types of controls irrespective inheritance in order to to apply it's custom toolbar styles. In your case your control is of type myimagebutton and not Button so the style is not set by the ToolBar which normally directly sets the Style property based on the type of the control using the two potential types of calls.
element.SetResourceReference(FrameworkElement.StyleProperty, styleKey);
element.DefaultStyleKey = styleKey;
BTW, in your case I believe only the second line is performed by the ToolBar control and styleKey at that point is defined as null.
Now instead of inheriting from Button in the first place you would probably be better off just to create a new ControlTemplate or a DataTemplate for your button and assigning into the Template or ContentTemplate property respectively through the use of a style. This way you are still always dealing with a button and the style is what changes the visual properties.
<Window x:Class="HeaderedContentControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="252"
Width="372">
<Window.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Background"
Value="Orange" />
</Style>
<DataTemplate x:Key="ImageButtonDataTemplate">
<Grid x:Name="grdButton">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Center">
</Image>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Text="{Binding}"
VerticalAlignment="Center"
Margin="2 0 2 0"
Background="Pink" />
</Grid>
</DataTemplate>
<Style x:Key="ImageButtonStyle"
TargetType="{x:Type Button}">
<Setter Property="ContentTemplate"
Value="{StaticResource ImageButtonDataTemplate}" />
</Style>
</Window.Resources>
<Grid Margin="11">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ToolBar>
<Button Style="{StaticResource ImageButtonStyle}"
Content="Some Text" />
</ToolBar>
<Button Grid.Row="1"
Style="{StaticResource ImageButtonStyle}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Content="Some Text" />
</Grid>
</Window>
Using the ContentTemplate allows you to redefine the inner contents of the Button without loosing all of the special button state transitions and other niceties you would normally like to keep.
See this related post on MSDN Forums that also explains similar behavior when adding a StackPanel containing buttons to a ToolBar.

How to wire up a click event for a custom usercontrol button? Should I use CustomControl?

I wanted to create a button that had an image and a textblock as content. So I went about looking for an answer and found a post (Reusable Custom Content for Buttons) which told me to create a usercontrol.
I did this and it works great. I can set the image source and text through dependency properties. However, I am stuck as there is no click event for my control.
I did a little more digging and concluded that I probably need a CustomControl derived from Button. Is this correct? Or would it be better to wire up a click event to my UserControl?
Here's my UserControl:
<UserControl x:Class="Client.Usercontrols.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" MinHeight="30" MinWidth="40"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Button Width="Auto" HorizontalAlignment="Center">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="Transparent" >
<Grid>
<Image Name="tehImage" Source="{Binding ImageSource}" />
<TextBlock Name="tehText" Text="{Binding Text}"
Style="{DynamicResource ButtonText}" />
</Grid>
</Border>
</Button>
</UserControl>
Implementation
<my:MyButton ImageSource="../Images/MainSyncButton.png" ImageWidth="141" Text="Synchronise" Click="btnSynchronise_Click" />
The easiest option would be to just make your UserControl expose a click event, and pass through your Button's click event.
In MyButton's xaml:
<Button Width="Auto" HorizontalAlignment="Center" Click="onButtonClick">
In MyButton's code:
public event RoutedEventHandler Click;
void onButtonClick(object sender, RoutedEventArgs e)
{
if (this.Click != null)
{
this.Click(this, e);
}
}
You can then leave your "implementation" code as-is.
The answer really depends on what your goals are for the control. You may be able to get away with not creating a user or custom control if you can manipulate the data that you are binding to. If all you want to do is display a dynamic image and text, then you could create an ImageText object that contains two properties. You could then bind the default Button control's Content property to this object and use a DataTemplate to define the layout of the content.
If you cannot control the data type that you are binding to, or if you're really set on the idea of creating a control then I would recommend creating a custom control. Custom controls allow you to utilize the built-in capabilities of a standard button. Generally you would only want to create a User Control if you wanted to hide or encapsulate the default functionality of the visual controls contained within the control.
Good luck.

Resources