WPF menu will not close when radiobutton group item is selected - wpf

I created a menuitem resource style that assists in showing a group of mutually exclusive selectable radio button items. When one of the radio button items is selected the menu will not close. I tried using StaysOpenOnClick but that doesn't seem to work. How can I get the menu to close when one of the radio button menu items is selected?
XAML:
<Window x:Class="WpfApp1.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:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<Grid>
<Menu>
<MenuItem Header="Menu" StaysOpenOnClick="False" >
<MenuItem.Resources>
<Style x:Key="GroupStyle1" TargetType="{x:Type RadioButton}">
<Setter Property="GroupName" Value="OptionGroup1"/>
</Style>
</MenuItem.Resources>
<MenuItem StaysOpenOnClick="False">
<MenuItem.Template>
<ControlTemplate>
<RadioButton
Content="Radio1"
Style="{StaticResource GroupStyle1}"/>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
<MenuItem StaysOpenOnClick="False">
<MenuItem.Template>
<ControlTemplate>
<RadioButton
Content="Radio2"
Style="{StaticResource GroupStyle1}"/>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
<MenuItem StaysOpenOnClick="False">
<MenuItem.Template>
<ControlTemplate>
<RadioButton
Content="Radio3"
Style="{StaticResource GroupStyle1}"/>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</MenuItem>
</Menu>
</Grid>

I usually try not to use code behind with WPF, but for things like this, I think it may be justified. I'm sure if you think long enough you can write a whole bunch of xaml that can do this, but here's a quick and slightly dirty way of doing so:
Name the MenuItem
Add an event handler to the style, and use that to close the menu in the code behind. (See the EventSetter inside the style)
Xaml
<Grid>
<Menu>
<MenuItem x:Name="menuItem" Header="Menu">
<MenuItem.Resources>
<Style x:Key="GroupStyle1" TargetType="{x:Type RadioButton}">
<Setter Property="GroupName" Value="OptionGroup1"/>
<EventSetter Event="Checked" Handler="RadioButton_Checked"/> <!--Add this-->
</Style>
</MenuItem.Resources>
...
Code Behind
private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
menuItem.IsSubmenuOpen = false;
}

Related

Can't set both ContentTemplateSelector and Template properties on a DataGridColumnHeader

In short, the question title says it all. For those that want more detail, here is the crux of my problem: I need to apply a custom ControlTemplate to the DataGridColumnHeader elements in my DataGrid control, but I also need to style them differently, depending on the cell data nearest the header. However, when I set both the ContentTemplateSelector and Template properties on a DataGridColumnHeader element, the DataTemplateSelector that is set as the value of the ContentTemplateSelector property is not called. Commenting out the Template property setting confirms this to be the case, as the DataTemplateSelector element will now be called.
Yes, I know that you guys love to see some code, but I have completely templated the whole DataGrid control to look like Excel, so as you can imagine, I have far too much code to display here. But just to please you code hungry devs, I've recreated my problem in a much simpler example... let's first see the XAML:
<Window x:Class="WpfApp1.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:Local="clr-namespace:WpfApp1"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.Items>
<System:String>One</System:String>
<System:String>Two</System:String>
<System:String>Three</System:String>
</DataGrid.Items>
<DataGrid.Resources>
<Local:StringDataTemplateSelector x:Key="StringDataTemplateSelector" />
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource StringDataTemplateSelector}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
</Grid>
</Window>
Now the most simple DataTemplateSelector class:
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
public class StringDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Debugger.Break();
return null;
}
}
}
In the XAML, we see a DataGrid, with just one DataGridTemplateColumn and three string values, one on each row, and some resources. There is a Style for the DataGridColumnHeader element in the Resource section, with the most simple ControlTemplate set up for it, that only includes the required named parts from the default ControlTemplate.
If you run the application as it is, then it will NOT currently break at the Debugger.Break() method in the StringDataTemplateSelector class. This is unexpected. If you now comment out the setting of the Template property in the Style and run the application again, then you will now see that program execution will now break at the Debugger.Break() method, as expected.
Further information:
In the Remarks section of the ContentControl.ContentTemplateSelector Property page of MSDN, it states that
If both the ContentTemplateSelector and the ContentTemplate properties are set, then this property is ignored.
However, it does not mention the Template property and there is also no mention of this on the Control.Template Property page on MSDN.
Furthermore, I tried this same setup using a simple Button control and can confirm that setting both the ContentTemplateSelector and the ContentTemplate properties on that does NOT stop the StringDataTemplateSelector class from being called:
<ItemsControl>
<ItemsControl.Resources>
<Local:StringDataTemplateSelector x:Key="StringDataTemplateSelector" />
<Style TargetType="{x:Type Button}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource StringDataTemplateSelector}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Ellipse Stroke="Red" StrokeThickness="1" Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding Height}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.Resources>
<Button Content="One" />
<Button Content="Two" />
<Button Content="Three" />
</ItemsControl>
So, what I'm after is a way to apply a custom ControlTemplate element to the DataGridColumnHeader objects, yet still be able to have the DataTemplateSelector class called during the rendering process.
add a content presenter in your controltemplate?
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" />
<ContentPresenter></ContentPresenter>
</Grid>
</ControlTemplate>

Overriding application wide style

I want to define a global style for textblock in the application but I also want to be able to override this default style. I always thought that the local override of style has more priority than the global one but it doesn't seems to be the case?
In the following example, the Button with content "Test" will have a "Red" foreground when I expect it to be "Aqua". If I remove the global style in Application.Resources, than it will works. Did I'm missing something?
App.xaml
<Application x:Class="ContextMenuTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>
MainWindow.xaml
<Window x:Class="ContextMenuTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type MenuItem}" x:Key="DefaultMenuItemStyle">
<Setter Property="Foreground" Value="DarkGreen" />
</Style>
<Style TargetType="{x:Type Button}" x:Key="DefaultButtonStyle">
<Setter Property="Foreground" Value="DarkGreen" />
</Style>
</Window.Resources>
<Grid Background="Black">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu 1" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 2" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 3" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 4" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 5" Style="{StaticResource DefaultMenuItemStyle}" />
</ContextMenu>
</Grid.ContextMenu>
<Button Content="Test" Style="{StaticResource DefaultButtonStyle}" Foreground="Aqua" />
</Grid>
Implicit TextBlock defined in App.xaml will not be overrided by other TextBlock styles. It's therefore recommended that you move your default TextBlock style to for example <Window.Resources>.
Please refer to the following links for more information about this.
Implicit styles in Application.Resources vs Window.Resources?
Over ride the Property setting in App.xaml: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f6822a5e-09c7-489b-b85d-833f1f9356dc/over-ride-the-property-setting-in-appxaml?forum=wpf
Or simply don't define any implicit TextBlock style. Define a default Style for each Control instead.
Your problem is in defining your application level resources for the TextBlock instead of the Button. Most of WPF controls use TextBlocks as default way to display text content, so by trying to override your Button Foreground, you are doing it, but then it gets overriden again by TextBlock default style.
Change your App.xaml to this and you will get the result you wanted to achieve:
<Application.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>

Context menu on any control on form

How would i display a context menu with a button in it by right-clicking on any element on form?
The purpose of a button in a form would be:
Displaying a x:Name of a control on which a right click(displaying a context menu )is performed.
To summarize, i want to right click on any element on form to display context menu with 1 button "Show me name" which should show messagebox displaying: "My name is [x:name of element]"
Define an implicit Style for each type of control:
<Window x:Class="WpfApplication1.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:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<ContextMenu x:Key="cm">
<MenuItem Header="Show name" Click="MenuItem_Click" />
</ContextMenu>
<Style TargetType="Button">
<Setter Property="ContextMenu" Value="{StaticResource cm}" />
</Style>
<Style TargetType="TextBox">
<Setter Property="ContextMenu" Value="{StaticResource cm}" />
</Style>
</Window.Resources>
<StackPanel>
<Button x:Name="a" Content="a" />
<TextBox x:Name="b" />
</StackPanel>
</Window>
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
ContextMenu cm = mi.Parent as ContextMenu;
FrameworkElement fe = cm.PlacementTarget as FrameworkElement;
MessageBox.Show(fe.Name);
}

How to change dxb:BarcheckItem background and foreground style

How to change the BarCheckITem background color, am having hardtime changing the styles for devexpress controls
<dxb:ToolBarControl ShowBackground="True" Grid.Row="0" HorizontalAlignment="Stretch"
VerticalAlignment="Top"
AllowCustomizationMenu="True"
BarItemDisplayMode="ContentAndGlyph" UseWholeRow="True"
AllowHide="False" AllowQuickCustomization="False" RotateWhenVertical="False">
<dxb:BarCheckItem Content="Forms"
Glyph="{dx:DXImage Image=AddItem_16x16.png}"
GroupIndex="-11"
BarItemDisplayMode="ContentAndGlyph"
LargeGlyph="{dx:DXImage Image=AddItem_32x32.png}" />
<dxb:ToolBarControl>
You need to override the BarCheckItemLink.CustomResources and then to add a style to override the default template. I have made a simple sample to show this:
<dx:DXWindow x:Class="BarCheckItemBackground.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
Title="MainWindow" Height="350" Width="525">
<Grid>
<dxb:BarManager ToolbarGlyphSize="Large">
<dxb:BarManager.Items>
<dxb:BarCheckItem x:Name="ItemNormal"
Content="I am normal"
Glyph="{dx:DXImage Image=AddItem_16x16.png}"
BarItemDisplayMode="ContentAndGlyph"
LargeGlyph="{dx:DXImage Image=AddItem_32x32.png}" />
<dxb:BarCheckItem x:Name="ItemNotNormal"
Content="I am not normal lol"
Glyph="{dx:DXImage Image=AddItem_16x16.png}"
GroupIndex="-11"
BarItemDisplayMode="ContentAndGlyph"
LargeGlyph="{dx:DXImage Image=AddItem_32x32.png}" />
</dxb:BarManager.Items>
<dxb:BarManager.Bars>
<dxb:Bar>
<dxb:Bar.DockInfo>
<dxb:BarDockInfo ContainerType="Top"/>
</dxb:Bar.DockInfo>
<dxb:BarCheckItemLink BarItemName="ItemNormal" />
<dxb:BarCheckItemLink BarItemName="ItemNotNormal">
<dxb:BarCheckItemLink.CustomResources>
<ResourceDictionary>
<Style TargetType="{x:Type dxb:BarCheckItemLinkControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dxb:BarItemLinkControl}">
<Grid>
<Border Background="Yellow"/>
<dxb:BarItemLayoutPanel x:Name="PART_LayoutPanel"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</dxb:BarCheckItemLink.CustomResources>
</dxb:BarCheckItemLink>
</dxb:Bar>
</dxb:BarManager.Bars>
</dxb:BarManager>
</Grid>
</dx:DXWindow>
And the output window:
Hope this helps

How to reduce margins on buttons inside WrapPanel in WP7?

I'm trying to make a 'palette' in WP7. Visually, I'm after a look similar to the keyboard (SIP) or the dialler. I'm trying to make the margins around the buttons smaller than what they are now.
I'm having a lot of trouble with doing this, however - I've tried setting different margin thicknesses both directly and by attaching a style, but can't seem to get the problem sorted.
Here's an image of what I've got at the moment (sorry I'm a new user so it's just a link):
http://i40.tinypic.com/bj8g9f.jpg
And here's the relevant XAML I'm using.
<phone:PhoneApplicationPage
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tk="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
x:Class="Mathflow.MainPage"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<Style x:Key="PaletteObjectStyle" TargetType="Button">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#1F1F1F"/>
</Setter.Value>
</Setter>
<Setter Property="Margin" Value="0" />
<Setter Property="BorderThickness" Value="0" />
</Style>
<Style x:Key="PaletteObjectText" TargetType="TextBlock">
<Setter Property="Margin" Value="8" />
</Style>
</phone:PhoneApplicationPage.Resources>
<StackPanel x:Name="LayoutRoot" DataContext="">
<Canvas x:Name="FlowContainer" Height="500">
</Canvas>
<ItemsControl x:Name="Palette" DataContext="{Binding Source={StaticResource FunctionsSource}}" ItemsSource="{Binding FunctionCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<tk:WrapPanel Orientation="Vertical" Height="200" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Style="{Binding Source={StaticResource PaletteObjectStyle}}">
<TextBlock Text="{Binding Display}" Style="{Binding Source={StaticResource PaletteObjectText}}"/>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</phone:PhoneApplicationPage>
Thanks very much! Any help would be greatly appreciated.
It appears that the WrapPanel applies a margin to the items it contains. There may be a way to retemplate it to override this, or (more simply) you could just set a negative margin on PaletteObjectStyle.
<Setter Property="Margin" Value="-6" />
You can also simplify your style bindings like this:
<Button Style="{StaticResource PaletteObjectStyle}">
<TextBlock Text="{Binding Display}" Style="{StaticResource PaletteObjectText}"/>
You can try setting Padding to 0. If that does not get you closer to what you need - just replace the entire Template of the button with your own ControlTemplate. You can extract the default template from the button using Blend. Just right click your button and select the option to edit template copy.
Personally I would not use a Button in this case if you are concerned about the Margins.
Instead use a Rectangle and Use the Gesture Lister to watch for the tap event (instead of a click) Only downside of this method is that you cannot use commanding from XAML but you could just launch the command in code if you require it.
See below: (Extract from http://bit.ly/lIleTe)
<Rectangle Fill="Orange" x:Name="rect">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="GestureListener_Tap" Hold="GestureListener_Hold" />
</toolkit:GestureService.GestureListener>

Resources