Get Text of a ContextMenu.ItemsSource generated MenuItem in WPF - c#

I´ve got a Click-method of a MenuItem in a ContextMenu. In this method, I need the text of the item I´ve clicked.
Here´s the code:
private void menuItemKostenstellen_Click(object sender, RoutedEventArgs e) { }
I already tried with e.Source but that didn´t work.
How can I get this?

Use following:
<ContextMenu Name="conKostenstelle" >
<MenuItem Header="Kostenstellen" Name="menuItemKostenstellen">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<EventSetter Event="Click" Handler="MenuItem_Click" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</ContextMenu>
LinkedList<String> kliste = kosrep.GetKostenstellen();
menuItemKostenstellenunter.ItemsSource = kliste;

try this
private void menuItemKostenstellen_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
string title = mi.Header.ToString();
}

Use ItemContainerStyle Property for Click Event on all MenuItems
<ContextMenu>
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<EventSetter Event="Click" Handler="MenuItem_Click" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>

Related

Hide context menu in TaskBar Icon after click "Exit"

When I click the exit button in context menu it still appears until the method finish.
<tb:TaskbarIcon Name="TrayIcon" IconSource="Icon.ico" ToolTipText="text" Visibility="Visible" MenuActivation="LeftOrRightClick">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu Name="ContextMenu">
<ContextMenu.Style>
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="ItemsPanel" Value="{StaticResource MenuTPL}"/>
</Style>
</ContextMenu.Style>
<MenuItem x:Name="LogIn" Click="LogIn_Click" Header="points"></MenuItem>
<MenuItem x:Name="Exit" Click="Exit_Click" Header="exit"></MenuItem>
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
And the c# code is:
private void Exit_Click(object sender, RoutedEventArgs e)
{
TrayIcon.Visibility = Visibility.Hidden;
TrayIcon.ContextMenu.Visibility = Visibility.Hidden;
Application.Current.Shutdown();
}
I can't put the shutdown to backgroud. Is there any way to solve it?
You have to leave the event handler. Use Dispatcher.BeginInvokefor it.
Dispatcher.BeginInvoke((Action)(()=> { Application.Current.Shutdown(); }));

How to retrieve DataRow from DataRow.ContextMenu event

How can a bind DataRow to the Tag property of the ContextMenu.MenuItem associated with that row?
Here is what I have so far:
<DataGrid.Resources>
<ContextMenu x:Key="RowContextMenu">
<ContextMenu.Items>
<!--This line doesnot work-->
<MenuItem Header="GoToElement" Click="Click_GoToElement" Tag="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=Row.Header}"/>
</ContextMenu.Items>
</ContextMenu>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="ContextMenu" Value="{StaticResource RowContextMenu}" />
</Style>
</DataGrid.RowStyle>
Then , click-event looks like this. I am receiving an error: object reference not set to an instance of an object
private void Click_GoToElement(object sender, RoutedEventArgs e)
{
try
{
var row = ((System.Windows.Controls.MenuItem)sender).Tag;
MessageBox.Show(row.ToString());
}
catch (Exception ex) { MessageBox.Show(ex.Message + "\n" + ex.StackTrace); }
}
Bind to the PlacementTarget of the parent ContextMenu:
<MenuItem Header="GoToElement"
Click="Click_GoToElement"
Tag="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.Header}"/>

Displaying a Tooltip for ComboBoxItem - works after moving the mouse, but not on first try

I'm using WPF ComboBox with only two items in the Combobox. I display the Tooltip for each ComboboxItem by comparing the item.Content to a property that one class includes like this :
private void OnMouseHover(object sender, MouseEventArgs e)
{
var lineSelected = (modelGPZ.GetLineWyList().FirstOrDefault(x => x.isSelected == true));
ComboBoxItem item = sender as ComboBoxItem;
if ((double)item.Content == lineSelected.LiniaWyComboBox[0])
{
item.ToolTip = "This is the first Item";
}
if((double)item.Content == lineSelected.LiniaWyComboBox[1])
{
item.ToolTip = "This is the second Item";
}
}
The problem is that when I open the Combobox for the first time I don't get the Tooltip... Strange because the method is called when I debug it. What is more weird, when I hover my mouse over one item, and then another and at last to the first one.. my tooltip shows up..
I tried changing the event to MouseEnter which does not even call the method and what I thought so other related events for this such kind of action.
MSDN ComboBox Class
XAML for calling the mentiod method:
<ComboBox.ItemContainerStyle >
<Style TargetType="{x:Type ComboBoxItem}">
<EventSetter Event="MouseMove" Handler="OnMouseHover"/>
</Style>
</ComboBox.ItemContainerStyle>
For MouseMove and MouseLeave work as mentioned. For GotFocus the problem is isEditable=True - focus stayes on the TextBlock unfortunatelly.
ComboBox in MainWindows.xaml:
<DataGridTemplateColumn Header="PRĄD POJEMNOŚCIOWY [A]" HeaderStyle="{StaticResource PRAD_POJEMNOSCIOWY}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="PradPojemnosciowyComboBox"
ItemsSource="{Binding LiniaWyComboBox, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedItemComboBox, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEditable="True"
IsReadOnly="False"
Text="{Binding Prad_pojemnosciowy, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsTextSearchEnabled="False"
IsSynchronizedWithCurrentItem="True"
PreviewKeyDown="PradPojemnosciowyComboBox_OnPreviewKeyDown">
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="SelectedValue" Value="{x:Null}">
<Setter Property="SelectedItem" Value="{Binding SelectedItemComboBox, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
<ComboBox.ItemContainerStyle >
<Style TargetType="{x:Type ComboBoxItem}">
<EventSetter Event="GotFocus" Handler="PradPojemnosciowyComboBox_GotFocus"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The behavior is logically imho. First you have no ToolTip for ComboBoxItem, on first time MouseMove ToolTip being set, but it's already too late to trigger it ToolTip(it seems ToolTip triggered earlier than MouseMove for ComboBoxItem being fired). So you can see the ToolTip only second time you enter the item.
Attach all to the GotFocus and it will work as expected:
<ComboBox.ItemContainerStyle >
<Style TargetType="{x:Type ComboBoxItem}">
<EventSetter Event="GotFocus" Handler="ComboBoxItem_GotFocus"/>
</Style>
</ComboBox.ItemContainerStyle>
private void ComboBoxItem_GotFocus(object sender, RoutedEventArgs e)
{
var lineSelected = (modelGPZ.GetLineWyList().FirstOrDefault(x => x.isSelected == true));
ComboBoxItem item = sender as ComboBoxItem;
if ((double)item.Content == lineSelected.LiniaWyComboBox[0])
{
item.ToolTip = "This is the first Item";
}
if ((double)item.Content == lineSelected.LiniaWyComboBox[1])
{
item.ToolTip = "This is the second Item";
}
}
Better way is to create in ViewModel a property ItemToolTip in the object, which is DataContext for the ComboBoxItem and bind it:
<ComboBox.ItemContainerStyle >
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Content="{Binding ItemToolTip}"/>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
Example how to prepare data in ViewModel:
public List<object> CbxItemsSource { get; set; } = InitCbxSource();
private static List<object> InitCbxSource()
{
var dblLst = new List<double>() { 1, 2, 3 };
return dblLst.Select(dbl => (object)new { ItemValue = dbl, ItemToolTip = "e.g. item index " + dblLst.IndexOf(dbl)}).ToList();
}
I think it's better option to use ToolTipOpening from ComboBox class than OnMouseHover.
Checkout my solution:
<ComboBox>
<ComboBoxItem ToolTip="" ToolTipOpening="ComboBox_OnToolTipOpening">13.42</ComboBoxItem>
<ComboBoxItem ToolTip="" ToolTipOpening="ComboBox_OnToolTipOpening">15.82</ComboBoxItem>
</ComboBox>
And now code-behind for ToolTip manipulation:
private void ComboBox_OnToolTipOpening(object sender, ToolTipEventArgs e)
{
ComboBoxItem item = sender as ComboBoxItem;
if (item.Content.Equals("13.42"))
{
item.ToolTip = "ToolTipItem1";
}
else if (item.Content.Equals("15.82"))
{
item.ToolTip = "ToolTipItem2";
}
}

ContextMenuOpening when opening a ContextMenu from a ListViewItem

I have a ListView with some data and an ItemContainerStyle to bind the ContextMenu to every item (so it only appears when clicking on an item in the ListView)
I've got the ContextMenu defined in ListView.Resources. How do I properly fire the ContextMenuOpening event and then access the ContextMenu in the ContextMenuEventArgs in said event?
ListView.Resources>
<ContextMenu x:Key="ItemContextMenu" FontFamily="Verdana" FontSize="14">
//Rest of the ContextMenu
<MenuItem Header="Custom Actions">
</MenuItem>
</ContextMenu>
</ListView.Resources>
Right now, I tried to have an Event Setter in the style,
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
<EventSetter Event="ContextMenuOpening" Handler="ContextMenu_ContextMenuOpening" />
</ListView.ItemContainerStyle>
but this triggers a NullPointerException here in the C#-Code (which is basically copied from https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/how-to-handle-the-contextmenuopening-event)
private void ContextMenu_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
FrameworkElement fe = e.Source as FrameworkElement;
ContextMenu cm = fe.ContextMenu;
List<MenuItem> customActions = new List<MenuItem>();
customActions.Add(new MenuItem {Header = "First Thing"});
customActions.Add(new MenuItem {Header = "Second Thing"});
foreach (MenuItem mi in cm.Items) // here is the NullPointerException
{
if((String)mi.Header == "Custom Actions")
{
foreach(MenuItem cmi in customActions)
{
mi.Items.Add(cmi);
}
}
}
}
How can I access the ContextMenu and modify it before opening?

Open Buttons ContextMenu on Left Click

I have a button with a context menu, my requirements are to show the context menu on left click
The problem is that the <ContextMenu ItemsSource="{Binding LineItems}" isn't being updated/refresh when the context menu opens. However If i right click first, items are loaded fine
XAML
<Button x:Name="BtnMessageChannel" Click="BtnMessageChannel_Click" Grid.Row="0" Grid.Column="2" Height="23" Width="23" ToolTip="Message Channel" >
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding LineItems}" x:Name="CtxMessageChannel">
<ContextMenu.Resources>
<Image x:Key="img" Source="{Binding Icon}" x:Shared="false"/>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding DisplayName}"/>
<Setter Property="Icon" Value="{StaticResource img}">
</Setter>
</Style>
</ContextMenu.Resources>
</ContextMenu>
</Button.ContextMenu>
<Image Source="Images/mail_send.png" HorizontalAlignment="Left" Width="16" />
</Button>
Code Behind
private void BtnMessageChannel_Click(object sender, RoutedEventArgs e)
{
BtnMessageChannel.ContextMenu.GetBindingExpression(ContextMenu.ItemsSourceProperty)
.UpdateTarget();
BtnMessageChannel.ContextMenu.Visibility = Visibility.Visible;
BtnMessageChannel.ContextMenu.IsOpen = true;
}
Is there any easy solutions to this problem?
An easy solution is to update your button event handler to simulate a right click if the context menu is not currently open.
private void BtnMessageChannel_Click(object sender, RoutedEventArgs e)
{
if (!BtnMessageChannel.ContextMenu.IsOpen)
{
e.Handled = true;
var mouseRightClickEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Right)
{
RoutedEvent = Mouse.MouseUpEvent,
Source = sender,
};
InputManager.Current.ProcessInput(mouseRightClickEvent);
}
}

Categories