WPF SplitButton? [closed] - wpf

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
I've just spent a very frustrating afternoon trawling Google looking for a commercial-grade WPF SplitButton control that will work in a ToolBar. A SplitButton is one where you can click on the main part of the Button to take a default action, or click on a little triangle on the right to get a drop-down menu of alternate actions).
I found several on the web (including the one on CodeProject, and including the two on CodePlex). None of them work properly in a ToolBar--they either don't appear at all, or they don't have toolbar button styling. I even looked at some commercial offerings, like ActiPro's pop-up button (in their SharedLibrary DLL). Same problems.
And yes, I've seen all the posts about how easy it is to create one. It's very easy to create a bad one, but not so easy to create one that looks and works like the SplitButtons in Outlook or Visual Studio, where the drop-down menu doesn't disappear if you release the mouse button.
So, here's my question: Are there any commercial-grade SplitButtons out there, either open-source or commercial, that work in toolbars? I'm not looking for a control that is part of a $1,500 annual subscription to somebody's controls library, but if there is a reasonably-priced SplitButton, I'd sure like to find it.

The only true "commercial-grade" split button that I know of is the one by Syncfusion, which is included as part of their ribbon controls (although it works outside of the ribbon as well).
That being said, I remember this implementation as being fairly usable and complete, if you're looking for something free.

Another good free implementation that seem to have it all:
http://huydinhpham.blogspot.com/2008/09/wpf-drop-down-and-split-button.html
The split button can be used in the toolbar and has a proper toolbar style. It can also be restyled if you want.
Dropdown menu is exposed via its own property - i.e splitbutton can have it's own context menu separate from the dropdown one (even though it seems illogical it can be useful in some cases - like toolbar context menu that pops up when you right click on a button placed in the toolbar).
The dropdown menu is standard ContextMenu - i.e. content can be databound, menu items restyled etc.
Both the main and the dropdown parts of the split button have command properties associated with them.

The Extended WPF Toolkit Community Edition (which is free) has a nice SplitButton (and it has a DropDownButton as well)
<xctk:SplitButton Content="Click Me">
<xctk:SplitButton.DropDownContent>
<xctk:ColorCanvas />
</xctk:SplitButton.DropDownContent>
</xctk:SplitButton>

I don't know what exactly you are looking for in a split button, but this video on how to create one is pretty complete and makes a splitbutton that is just about perfect.
http://windowsclient.net/learn/video.aspx?v=3929
I know you didn't want a tutorial, but I've used this before and you couldn't tell the difference between it and the ones in outlook.

There is a pretty good split button implementation for WPF and Silverlight over Delay's blog:
Banana SplitButton (A WPF-specific fix for SplitButton and some code analysis improvements for the Silverlight version, too)

I think what you mean is called a DropDownButton.
There is a boolean property on MenuItem "StaysOpenOnClick" which could solve your problem.

I was looking for the same and just rolled my own (you will need to style to your liking (to match the ToolBar) and you could refactor it / convert it into a custom control ... etc.)
<StackPanel x:Name="Split" Orientation="Horizontal">
<Button Command="{Binding MainCommand}">
<StackPanel>
<Image Source="{StaticResource MainCommandImage}"/>
<TextBlock>MainCommand</TextBlock>
</StackPanel>
</Button>
<Separator HorizontalAlignment="Left" Width="1" VerticalAlignment="Stretch" Margin="0,5"/>
<CheckBox Width="16" IsThreeState="False">
<Grid>
<Path Fill="Black" Data="{StaticResource DownArrowGeometry}"
Stretch="Uniform" Height="6" Width="6" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Popup x:Name="popupOptions" AllowsTransparency="True" PopupAnimation="Fade" StaysOpen="False"
Placement="Bottom" PlacementTarget="{Binding ElementName=Split}" HorizontalOffset="-3"
IsOpen="{Binding RelativeSource={RelativeSource AncestorType={x:Type CheckBox}, AncestorLevel=1}, Path=IsChecked}">
<StackPanel>
<StackPanel>
<Image Source="{StaticResource SubCommandImage1}"/>
<TextBlock>SubCommand1</TextBlock>
</StackPanel>
<StackPanel>
<Image Source="{StaticResource SubCommandImage2}"/>
<TextBlock>SubCommand2</TextBlock>
</StackPanel>
</StackPanel>
</Popup>
</Grid>
</CheckBox>
</StackPanel>

Using the WPF Toolkit split button to show a context menu is reasonably straight forward. Add a context menu in your window resources. On the window load - bind the context menu to the split button and then use the context menu as you would do normally.
It really needs to be added in the WPF Toolkit as the majority use case for this button is to replicate the old WinForm Splitt button.
<Window x:Class="SplitButtonTesting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ContextMenu x:Key="contextMenu" IsOpen="{Binding IsOpen}">
<MenuItem Header="One" />
<MenuItem Header="Two" />
<MenuItem Header="More...">
<MenuItem Header="One" />
<MenuItem Header="Two" />
</MenuItem>
</ContextMenu>
</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top" x:Name="ApplicationMenu">
<xctk:SplitButton x:Name="SplitButton" Content="Main Button" DropDownContent="{x:Null}" />
</Menu>
<Border />
</DockPanel>
Code behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace SplitButtonTesting
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
SetupSplitButton();
}
public void SetupSplitButton()
{
var menu = this.Resources["contextMenu"] as ContextMenu;
menu.PlacementTarget = SplitButton;
menu.Placement = PlacementMode.Bottom;
menu.DataContext = SplitButton;
}
}
}

Related

Why do my commandbindings only work if button is in toolbar?

I have a window with a toolbar which contains some buttons with commands.
The Buttons stopped working since i replaced the toolbar with a stackpanel containing the buttons.
In my understanding this shound not make any difference. The buttons still have the Command property set, i did not change anything in my custom commands class and the CommandBinding are also still the same. They are implemented some grids and usercontrols deeper than the button, but they do work, as long as the buttons are in a ToolBar control!
If i implement CommandBindings directly in the Window they work (but that is not what i want)
Here's the code (abridged):
<Window>
<Grid>
<StackPanel>
<Button Command="gui:GuiCommands.Hello">Hello</Button>
</StackPanel>
<Grid>
<TabControl>
<TabItem Header="MyTab">
<Grid>
<Grid.CommandBindings>
<CommandBinding Command="gui:GuiCommands.Hello" Executed="hello_Clicked"/> <!-- THIS WOULD NOT WORK -->
</Grid.CommandBindings>
<Grid>
</TabItem>
</TabControl>
</Grid>
</Grid>
<Window.CommandBindings>
<CommandBinding Command="gui:GuiCommands.Hello" Executed="hello_Clicked"/> <!-- THIS WOULD WORK -->
</Window.CommandBindings>
</Window>
I know it would not compile but i had to simplify it. This works as soon as i replace "StackPanel" with "ToolBar" with my app. How can that be?
Okay, i guess is figured it out by my self again (why does this always happen right after i posted the question?)
Short: I needed to set FocusManager.IsFocusScope="true" on the StackPanel
Long: see the answer to this question: Do I have to use CommandTarget? I thought any focused element would receive the Command
A StackPanel only arranges child elements into a single line that can be oriented horizontally or vertically.
While a Toolbar provides a container for a group of commands or controls.
So what happens if you put a StackPanel element inside of the ToolBar
<ToolBar>
<StackPanel>
<Button Command="gui:GuiCommands.Hello">Hello</Button>
</StackPanel>
</ToolBar>

I want to reuse a library of WPF UserControls - How can I set the styles?

I have created a WPF desktop application using the MVVM pattern. As part of this effort, I have created a namespace with many dialog windows, dialogViewModels and dialogViews. The dialog windows typically display one of the dialogViews, depending on the assigned dialogViewModel.
I now want to convert the Views and ViewModels in this namespace to a separate library, so that I may reuse the dialogs in other applications. However, I have two questions:
How can I set the styles on my usercontrols so that, when the library is used in a different application, it uses the styles from that application.
Will I able to override datatemplate assignments made in the library controls when reusing the library?
Some code to illustrate my point:
<Window x:Class="FeehandlerMain.Dialogs.OKDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Binding Path=DialogTitle}"
Height="200" Width="400" ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True" WindowStartupLocation="CenterOwner" SizeToContent="Height">
<Window.Resources>
<DataTemplate DataType="{x:Type dialogs:MessageBoxDialogViewModel}">
<dialogs:MessageBoxDialogView />
</DataTemplate>
</Window.Resources>
<Border Style="{StaticResource StandardBorderStyle}" >
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding}"
Grid.Column="0" Grid.Row="0" />
<StackPanel Orientation="Horizontal"
Grid.Column="0" Grid.Row="1">
<Button Content="OK" IsDefault="True" IsCancel="True"
Style="{StaticResource StandardButtonStyle}"/>
</StackPanel>
</Grid>
</Border>
</Window>
Question 1 is regarding the use of StandardBorderStyle and StandardButtonStyle. These styles are currently defined in my App.xaml file under <Application.Resources>. If I put the dialogs in a library, and I reference that library from a new application, how can I get the dialog to use StandardBorderStyle and StandardButtonStyle from the new application, so that each application can define it's own visual style?
Question 2 is regarding the DataTemplates. These templates are used to select the appropriate view for the Dialog (inserted as a ContentControl element in the example above), based on the type of ViewModel assigned as the Dialog's DataContext. Will I be able to override the above DataTemplate when reusing the library, in a scenario where I want to use a different View than MessageBoxDialogView for MessageBoxDialogViewModel?
Oh and I know it's two questions, but you will still just get reputation for one answer, sorry! ;-)
For the styles, the best way I can think of is to define a DependencyProperty for each of them in your own UserControl. So you'll have, for example, a DependencyProperty called BorderStyle which you set the default to the style you define internaly in your control library, while still allowing the client code using your control to override this style the way they want.
For the DataTemplate, you wouldn't really have to do anything, since the user of your library can define a another DataTemplate (for example for MessageBoxDialogViewModel) in his code, and that would take precedence and be used instead of the default one.
Hope this helps :)

VS2010 WPF - Can I create a menu with menu items just via the UI (not editing XAML?)

Just trying to drag my first Menu control onto a WPF application in VS2010.
Is there a way to (via the VS2010 UI) setup the menu items etc? Or does one have to jump into the XAML to do this?
Also it seems like the Menu control, after I drag it onto the window, exists at the top of the Window. However I was expecting it to be rendered as a typical Windows menu where it's right at the top associated with the window itself (not the window contents), if that makes sense. Does the VS2010 "menu" item from the toolbox give you the "traditional" windows application menu?
I would really encourage you to read up on Panels (and Attached Properties) before you start playing with the controls to understand how they are laid out (Especially the difference between Panels and ContentControls is key). In WPF panels decide how the controls are laid out (at least the basics within which controls get a wee say). It sounds much like you are trying to do WPF the WinForms way - and you will end up really frustrated and needing lots of tranquillizers before the hour turns nigh... :)
In the VS Studio the template uses a Grid as the basis for layouting - which by default centers and stretches content (as well as overlaying controls), so just dragging a menu in there will provide insensible designs.
As for jumping into XAML - I never use the ToolBox and the Visual Designer. It's a matter of taste of course, but if you're used to using VS (in contrast to Blend), I find it easier to understand what is happening when I edit the raw XAML.
A few starter resources: link and link. And for a simpler learning environment for getting started - I enjoyed Kaxaml a lot (which is an editor build in XAML/WPF albeit in .Net 3.5 sp1).
EDIT: A small sample - just copy everything between the Window-tags and paste it between the ones in your template that Visual Studio gives you:
<Window ....>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Open"/>
<MenuItem Header="_Save"/>
<MenuItem Header="_Exit"/>
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Header="C_ut"/>
<MenuItem Header="_Copy"/>
<MenuItem Header="Paste"/>
</MenuItem>
<MenuItem Header="Help">
<MenuItem Header="About"/>
</MenuItem>
</Menu>
<GroupBox Header="Some interesting controls go here">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="_First property"/>
<TextBox Grid.Column="1"/>
<Label Grid.Row="1" Content="_Second property"/>
<TextBox Grid.Column="1" Grid.Row="1"/>
</Grid>
</GroupBox>
</DockPanel>
</Window>

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