Is there a way to programatically close a menuitem in WPF - wpf

I have a menu in wpf that has an input box and a button on it. Once the user clicks the button I need to close the menu.
Is there a way to do this?
<Menu x:Name="MainMenu">
<MenuItem Header="Main">
<MenuItem Header="SubMenu" x:Name="SubMenu">
<StackPanel Orientation="Horizontal">
<TextBox Width="50" x:Name="TextBox" />
<Button Content="Click Me and Close" x:Name="Button" IsDefault="True"/>
</StackPanel>
</MenuItem>
</MenuItem>
Thanks,
Jon

Get hold of the MenuItem and do:
_menuItem.IsSubmenuOpen = false;
Easy way to get hold of it:
<Button x:Name="_button" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}, AncestorLevel=2}"/>
Code-behind:
_button.Click += delegate
{
(_button.Tag as MenuItem).IsSubmenuOpen = false;
};

I find that using IsSubmenuOpen doesn't properly eliminate focus from the Menu containing the MenuItem (especially if the Menu is in a ToolBar - the top-level MenuItem remains Selected even though the menu is "Closed"). I find sending a MouseUp event to the MenuItem works better (in the button's, or nested control's, Click event handler):
private void button_Click(object sender, RoutedEventArgs e) {
Button b = sender as Button;
if (b == null || !(b.Parent is MenuItem))
return;
MenuItem mi = b.Parent as MenuItem;
mi.RaiseEvent(
new MouseButtonEventArgs(
Mouse.PrimaryDevice, 0, MouseButton.Left
)
{RoutedEvent=Mouse.MouseUpEvent}
);
}

Steve thanks for your solution. That is actually right answer, and finally something that really works beside of tons of bad answers over the internet. I have a shorter (and more safe) solution based on your anwser. Because direct parent (e.Parent) of the button is not always MenuItem (from original answer that is StackPanel), your solution will not work. So just set the Name property of the MenuItem (Name="MyMenuItem") and hook this handler on the Button:
private void Button_Click(object sender, RoutedEventArgs e) {
MyMenuItem.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) {
RoutedEvent = Mouse.MouseUpEvent
});
}

Related

Xceed PropertyGrid AdvancedOptionsMenu context menu example

I'm trying to get a "Copy" context menu to display when clicking on the advanced options icon of any property. What do I need to add to make it work?
<xctk:PropertyGrid
x:Name="PropertyGrid"
Grid.Column="1" Margin="8"
ShowSummary="False"
AutoGenerateProperties="True"
HideInheritedProperties="False"
SelectedObject="{Binding InspectedObject}"
SelectedObjectName="{Binding InspectedObject, Converter={StaticResource PropertyGridPropertyNameConverter}}"
SelectedObjectTypeName="{Binding InspectedObject, Converter={StaticResource PropertyGridPropertyTypeConverter}}"
SelectedObjectChanged="PropertyGrid_OnSelectedObjectChanged"
ShowAdvancedOptions="True"
>
<xctk:PropertyGrid.AdvancedOptionsMenu >
<ContextMenu>
<MenuItem Header="Copy" Click="MenuItem_OnClick"></MenuItem>
</ContextMenu>
</xctk:PropertyGrid.AdvancedOptionsMenu>
</xctk:PropertyGrid>
I'd like the "Copy" context item to display and take a click whether or not the property is read only.
In the MenuItem click event handler, you can access property data by property DataContext in sender object.
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
{
MenuItem menuItem = sender as MenuItem;
if (menuItem != null && menuItem.DataContext is PropertyItem)
{
Clipboard.SetData(DataFormats.Text, ((PropertyItem)menuItem.DataContext).Value);
}
}
In the following link, you can find more information about this topic:
https://kmatyaszek.github.io/2018/08/22/extended-wpftoolkit-propertygrid-copybutton.html
I have noticed that this solution works when you clicked (left mouse button) at AdvancedOptionsMenu icon, there is a problem with the right mouse click on the property item. To solve this problem I forked the original repo and I have added copy value menu item to AdvancedOptionsMenu. Check it out: https://github.com/kmatyaszek/wpftoolkit

TextBlock MouseDown URL - How get my url in my code behind?

I ve a list from sharepoint and i collect from this list an hyperlink.
As i want my textbox to be like an hyperlink I ve added an event on mousedown to open this hyperlink, My concern is how to collect this hyperlink in the codebehind with the sender.
For the moment I've just hide this hyperlink in the tooltip maybe i can manage this differently any suggestion will be grantly appreciated.
My point so far, i don't know how to get this tooltip in the code behind.
Thanks
My XAML Code :
<ListBox Name="ListboxTips" ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}" Height="20"></Image>
<TextBlock MouseDown="TextBlock_MouseDown_URL" TextDecorations="Underline"
Margin="10,10,20,10" Width="160" TextWrapping="Wrap"
Text="{Binding Path=TitleTip}"
ToolTip="{Binding Path=URL}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My code behind :
foreach (SPSClient.ListItem item in TipsList)
{
var tips = new Tips();
tips.TitleTip = item.FieldValues.Values.ElementAt(1).ToString();
tips.App = item.FieldValues.Values.ElementAt(4).ToString();
// get the Hyperlink field URL value
tips.URL = ((FieldUrlValue)(item["LinkDoc"])).Url.ToString();
//should collect the description of the url
//tips.URLdesc = ((FieldUrlValue)(item["LinkDoc"])).Description.ToString();
tips.Picture = item.FieldValues.Values.ElementAt(4).ToString();
colTips.Add(tips);
}
ListboxTips.DataContext = colTips;
....
private void TextBlock_MouseDown_URL(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//string test = (ToolTip)(sender as Control).ToString();
System.Diagnostics.Process.Start("http://www.link.com");
//System.Diagnostics.Process.Start(test);
}
Thanks a lot,
You can just access the property directly. It is not elegant, but will work!
private void TextBlock_MouseDown_URL(object sender, MouseButtonEventArgs e)
{
TextBlock txtBlock = sender as TexBlock;
// just access the property
string url = txtBlock.ToolTip as string;
}
A more elegant approach might be to use a Button, Hyperlink or something that exposes a Command, so that you can bind the 'click' action to a command on your view model that performs the action you wish to execute.
usually you stick any data you want to trespass somewhere to Tag attribute.
<TextBlock .. Tag="{Binding Path=URL}" />
This is easily retrievable as a public property:
private void TextBlock_MouseDown_URL(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var tb = sender as TextBlock;
if(tb != null)
{
var neededUrl = tb.Tag;
}
}

How to Identify button for list item

How do i access the object UserNames, that is bound to the list??
What i did so far:
Item of the list is object in my case:
new List<UserNames>();
this.users.Add(new UserNames() {Id = 1, UserName = "name 1"});
I am using data template for which i have label and button.
My List is as follows:
<ListBox Grid.Column="1" Grid.Row="1" Name="listBox1" ItemsSource="{Binding}" SelectedValuePath="Id">
<ListBox.ItemTemplate>
<DataTemplate>
<WrapPanel Orientation="Vertical">
<StackPanel>
<Label Content="{Binding UserName}" />
</StackPanel>
<StackPanel Name="ButtonStackPanel">
<Button Name="MyButton" Content="Click Me" Click="MyButton_Click">
</Button>
</StackPanel>
</WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Where my method for Button is. As you can see i did try to utilise the parent option, but without sucess
private void MyButton_Click(object sender, RoutedEventArgs e)
{
//StackPanel panel = (StackPanel)((Button)sender).Parent;
//WrapPanel wrapPanel = (WrapPanel) panel.Parent;
//ListItem listItem = (ListItem) wrapPanel.Parent;
//ListBox box = (ListBox) listItem.Parent;
//UserNames itemToReport = (UserNames) (box.SelectedItem);
//MessageBox.Show(itemToReport.UserName);
}
You can use the Button's DataContext, since it will be your UserName object
private void MyButton_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
UserNames data = b.DataContext as UserNames;
MessageBox.Show(data.UserName);
}
I've always thought that with WPF, your application is the DataContext, while the UI objects like Buttons, ListBoxes, TextBoxes, etc are simply a pretty layer that sits on top of the DataContext to allow the User to interact with it.
In the XAML, set the Tag property to the current item.
In the click handler, cast it back.
Usernames user = (sender as Button).Tag as Usernames;
To bind a datacollection it is often easiest to use an ObservableCollection (if the data is changing runtime). When you do the binding you have to define a datacontext, a datasoure and a datapath. I will advice you to read some more about binding on MSDN :D
This will work for you -
MessageBox.Show(((sender as Button).DataContext as UserNames).UserName);

WPF Toggle Button Checked/Uchecked event with one handler

I am using a ToggleButton in a WPF window:
<ToggleButton Height="37"
HorizontalAlignment="Left"
Margin="485.738,254.419,0,0"
VerticalAlignment="Top"
Width="109"
IsEnabled="True"
Checked="toggleAPDTimeoutErr_Checked"
Unchecked="toggleAPDTimeoutErr_Unchecked">Timeout</ToggleButton>
I have two events that I am monitoring, but this is done in two different code behind handlers. How can this be done in only one?
I will have many ToggleButtons, and the code can get large.
You can attach a single click event of your ToggleButton and in its handler you can check the ToggleButton IsChecked property by type casting the sender object in your handler like this -
private void ToggleButton_Click(object sender, RoutedEventArgs e)
{
if((sender as ToggleButton).IsChecked)
{
// Code for Checked state
}
else
{
// Code for Un-Checked state
}
}
Xaml:
<ToggleButton Height="37" HorizontalAlignment="Left" Margin="485.738,254.419,0,0" VerticalAlignment="Top" Width="109" IsEnabled="True" Click="ToggleButton_Click">Timeout</ToggleButton>
You should not use Click event as some answers suggest, because it will not work when the property IsChecked is changed by code or any other event than mouse (keyboard, animation..). This is simply a bug.
Instead you can use the same handler for both Checked and Unchecked and do action depending on IsChecked property.
<ToggleButton
Checked="toggleButton_IsCheckedChanged"
Unchecked="toggleButton_IsCheckedChanged" />
Try this
private void tBtn_super_Click(object sender, RoutedEventArgs e)
{
if (tBtn_super.IsChecked == true)
{
MessageBox.Show("True");
}
else
{
MessageBox.Show("False");
}
}

How to switch ribbon tab programmatically?

I have a ribbon in my view named 'ribbon' that have 2 tabs as below sample codes. I want Button1 when clicked will open Tab2 and vice versa. How would I do this?
<ribbon:Ribbon x:Name="ribbon" HelpPaneContent="{x:Static data:WordModel.Help}">
<ribbon:RibbonTab Header="Tab1" ... >
<ribbon:RibbonGroup x:Name="Button1" >
<ribbon:RibbonButton Clicked="SwitchToTab2" />
</ribbon:RibbonGroup>
</ribbon:RibbonTab>
<ribbon:RibbonTab Header="Tab2" ... >
<ribbon:RibbonGroup x:Name="Button2" >
<ribbon:RibbonButton Clicked="SwitchToTab1" />
</ribbon:RibbonGroup>
</ribbon:RibbonTab>
...
</ribbon:Ribbon>
You only have to trigger the IsSelected property of your tabs
private void SwitchToTab1(object sender, MouseButtonEventArgs e)
{
ribbontab1.IsSelected = true;
}
private void SwitchToTab2(object sender, MouseButtonEventArgs e)
{
ribbontab2.IsSelected = true;
}
Found myself: If your ribbon control named 'Ribbon' then call this in your button's clicked handler:
Ribbon.SelectedIndex = indexOfTab;
Hope that would help anyone with the same problem with me.
Simple, using:
ribbonName.Tabs[TabNumber].IsSelected=true;
I my opinion that is purely layout related stuff so I would attach an eventhandler to the buttons to change the SelectedTab.

Resources