How to display listbox on MenuItem? - c#

I have a WPF code like this:
<ListBox SelectedItem="{Binding SelectedItem}">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Click="MenuItem_Delete_Click" />
<MenuItem Header="Replace" Click="MenuItem_Replace_Click">
<ListBox SelectionMode="Single" SelectedItem="{Binding ReplaceItem}" />
</MenuItem>
<MenuItem Header="Insert" Click="MenuItem_Insert_Click">
<ListBox SelectionMode="Single" SelectedItem="{Binding InsertItem}}" />
</MenuItem>
</ListBox>
But this goes like follows:
When Mouse leave
When Mouse On
So how should I fix this?Thanks in advance!

Instead of using a listbox on the MenuItem, why don't you try to add menuitems to the existing menuitem (for your case is "Insert" and "Replace")
Let"s see my example.
MenuItem mi = new MenuItem();
mi.Header = "PX1-20T-D-B";
NameOfYourMenuItem.Items.Add(mi);
mi.Click += new RoutedEventHandler(MenuItemClick);
You can also add the eventHandler for each one of them.

Instead of using a ListBox in the MenuItem or adding sub menu items in code behind, try using DataTemplates. I assume that you have a collection containing your list box items.
<MenuItem Header="Replace" Click="MenuItem_Replace_Click" ItemsSource="{Binding ReplaceItemsCollection}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}" Click="replaceSubMenuItem_Clicked"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<MenuItem Header="Replace" Click="MenuItem_Replace_Click" ItemsSource="{Binding InsertItemsCollection}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}" Click="insertSubMenuItem_Clicked"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
In your code behind add:
private void replaceSubMenuItem_Clicked(object sender, EventArgs e)
{
// sender is the MenuItem. Just parse it.
}
private void insertSubMenuItem_Clicked(object sender, EventArgs e)
{
// ...
}

Related

How to make dropdown button's flyout auto close after selected an item?

How do I have the dropdown button flyout auto close after user selected an item?
Here is the XAML:
<DropDownButton Content="{x:Bind CurrentMode, Mode=OneWay}" >
<DropDownButton.Flyout>
<Flyout>
<ListView x:Name="testListView" ItemsSource="{x:Bind mDropdownItems, Mode=OneWay}"
SelectionMode="Single" SelectedItem="{x:Bind CurrentMode, Mode=TwoWay}"
SelectionChanged="OnSelectionChanged" >
<ListView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{x:Bind}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Flyout>
</DropDownButton.Flyout>
</DropDownButton>
Code Behind:
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listView = sender as ListView;
// if I add this, the flyout will not show correctly probably due to hiding during initialization.
//testListView.Hide();
NotifyPropertyChanged("CurrentMode");
}
In your OnSelectionChanged event just add this line of code:
DropDownButton.Flyout.Hide();

How can i get Menu item from menu with dataSource in WPF

I have menu with XML like this:
<MenuItem x:Name="MenuItemCameras" Header="Cameras" ItemsSource="{Binding LocalCameras}" >
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding DisplayName}" IsCheckable="True" IsChecked="{Binding IsStreamingVideo}" IsEnabled="{Binding CanStreamVideo}"
Command="{Binding DataContext.CommandSelectLocalCamera, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
Click="MenuItemCameras_OnClick"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
I want to iterate like this:
foreach (MenuItem mMenuItem in MenuItemCameras) {
//some code
}
How can I do this ?
To retrieve the corresponding MenuItem, you can do this
foreach (var item in MenuItemCameras.Items) {
MenuItem menuItem = (MenuItem)MenuItemCameras.ItemContainerGenerator.ContainerFromItem(item);
//some code
}
But there's a downside, as long as the corresponding MenuItem isn't created ItemContainerGenerator.ContainerFromItem will return null

How do I create a Menu dynamically instead of hard coded in the XAML?

I have successfully created a drop-down list in the XAML using a
.XAML
<Grid>
<DockPanel>
<Menu>
<MenuItem Header="Menu">
<MenuItem Header="{Binding Path=ddlXferData1}" Command="{Binding Path=XferData}" Click="MenuItem_Click" IsCheckable="True"/>
<MenuItem Header="{Binding Path=ddlXferData2}" Command="{Binding Path=XferData}" Click="MenuItem_Click" IsCheckable="True"/>
<MenuItem Header="{Binding Path=ddlXferData3}" Command="{Binding Path=XferData}" Click="MenuItem_Click" IsCheckable="True"/>
<Separator />
<MenuItem Header="{Binding Path=ddlSkillData1}" Command="{Binding Path=SkillData}" Click="MenuItem_Click" IsCheckable="True"/>
<MenuItem Header="{Binding Path=ddlSkillData2}" Command="{Binding Path=SkillData}" Click="MenuItem_Click" IsCheckable="True"/>
<MenuItem Header="{Binding Path=ddlSkillData3}" Command="{Binding Path=SkillData}" Click="MenuItem_Click" IsCheckable="True"/>
</MenuItem>
</Menu>
</DockPanel>
</Grid>
.xaml.cs
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem mnItem = (MenuItem) e.OriginalSource;
this.Model.menuItemSelected = (string) mnItem.Header;
}
From here the Commands XferData and SkillData are used to reference the event handler method that basically does something depending on the this.Model.menuItemSelected
All of this is working properly and the way I need it to work.
However, now I need the Menu (drop-down list) options to be build or created dynamically.
I am not 100% sure what is the best course of action to design and implement a dynamic drop-down list:
Should I put a in the .xaml
<Button Name="MenuButton" Content="{Binding Path=btnMenu}" Command="{Binding Path=Menu}" Click="button1_Click" .../>
and in the .xaml.cs build the Menu with options
private void button1_Click(object sender, RoutedEventArgs e)
{
// Make the main menu.
Menu mainMenu = new Menu();
DockPanel dockPanel = new DockPanel();
dockPanel.Children.Add(mainMenu);
mainMenu.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
mainMenu.VerticalAlignment = System.Windows.VerticalAlignment.Top;
// Make the menu items.
MenuItem menuItem = new MenuItem();
.....
}
or
Should I dynamically build the XAML?
it's not recommended but you can do it like this :
//assuming you have Menu named MainMenu and you want to add Menu Item to it and Sub menu item to the item which you have just added
MenuItem MainItem = new MenuItem();
MainItem .Header = "Main Item";
this.MainMenu.Items.Add(MainItem);
MenuItem SubItem= new MenuItem();
SubItem.Header = "Sub Item";
SubItem.Click += new RoutedEventHandler(SubItem_Click);
MainItem.Items.Add(SubItem);

ContextMenu CanExecute is not updated

I have a problem regarding the state of a menuitem in ContextMenu. I have a ObversableCollection of Cars. The cars are visualized in a ListBox, for each ListBox Item I want a ContextMenu. In that ContextMenu there is an option ReserveCar.
They problem I'm having is that the CanExecute of the Car is only executed once when I right click any car. They CanExecute will not be called anymore after that when I right click an other Car.
This causes that when I rightclick a Car which can be Reserved, the MenuItem is active, but when I then rightclick another which I should not be able to reserve the MenuItem remains active (because CanExecute is not called again).
<ListBox
ItemsSource="{Binding Cars}"
SelectedItem="{Binding SelectedCar}">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Reserve Car"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"
Command="{Binding ReserveCarCommand}">
<MenuItem.Icon>
<Image Source="{StaticResource ReserveCarIcon}" Width="24" Height="24"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
My ViewModel:
private RelayCommand<Car> _reserveCarCommand;
public ICommand ReserveCarCommand
{
get { return _reserveCarCommand ?? (_reserveCarCommand = new RelayCommanReserveCar, CanReserveCar)); }
}
public bool CanReserveCar(Car car)
{
return !car.IsReserved && ReservationsAreOpen;
}
public void ReserveCar(Car car)
{
car.IsReserved = true;
}
Also when I manually refresh the Command when doing something, the CanExecute is called with a null as parameter, so thats not working either.
if (_reserveCarCommand != null) _reserveCarCommand .RaiseCanExecuteChanged();
Try binding the context menu on ListBoxItem instead of ListBox. As binding of context menu for ListBox happen only at the fist right click so CanExectute will not fire after first right click.
<ListBox Name="simpleListBox"
ItemsSource="{Binding Cars}"
SelectedItem="{Binding SelectedCar}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
...
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

Change the header/content in class system.windows.controls.menuitem?

I have a c#, WPF application with the notification in taskbar. And the design like this:
I want the app could tell the notification icon is clicked. For example, if you clicked on the Change status, it will be like this:
The code in main window design is like this:
<ContextMenu>
<MenuItem
Header="LeftClicked"
Click="NodifierClick"/>
<Separator/>
<MenuItem Header="Reset" Click="NotifyIconClickReset" />
<MenuItem Header="Show" Click="NotifyIconClickShow" />
<MenuItem Header="Hide" Click="NotifyIconClickHide" />
<MenuItem Header="Close" Click="NotifyIconClickClose" />
<Separator/>
<MenuItem Header="Exit" Click="NotifyIconClickExit" />
</ContextMenu>
I have no idea that how to change the Header in the class System.Windows.Control.MenuItem, somebody has the solution?
This is the quick and dirty way:
private void NotifyIconClickReset(object sender, RoutedEventArgs e)
{
((MenuItem)sender).Header = "LeftClicked";
}
But if you want to have a consistent reference to the menu item and make sure nothing else has its header changed by accident, you could give the item a name and reference it instead:
<MenuItem x:Name="_resetMenu" Header="Reset" Click="NotifyIconClickReset" />
private void NotifyIconClickReset(object sender, RoutedEventArgs e)
{
_resetMenu.Header = "LeftClicked";
}

Categories