I got a ResourceDictionary in my WPF project. The entire project is meant to be running in background. In ResourceDictionary there is a context menu, code is here;
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Commands="clr-namespace:_365Drive.Office365.NotificationManager"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:local="clr-namespace:_365Drive.Office365.NotificationManager">
<LinearGradientBrush x:Key="MenuBackground" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White" Offset="1" />
<GradientStop Color="White" Offset="0.259" />
</LinearGradientBrush>
<ContextMenu x:Shared="false" x:Key="SysTrayMenu" Name="contextMenu">
<MenuItem Header="Sign in" Command="{Binding ShowAuthForm}" CommandParameter="{Binding}" />
<MenuItem Header="Prompt MFA now" Name="MFA" Command="{Binding ClearMFACacheCommand}" CommandParameter="{Binding}" Visibility="{Binding MFAVisibility}" />
<MenuItem Header="Sign out" Command="{Binding SignOutApplicationCommand}" CommandParameter="{Binding}" />
<Separator />
<MenuItem Header="Update Drive Mappings" Command="{Binding RefreshSettingsCommand}" CommandParameter="{Binding}" />
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
</ContextMenu>
</ResourceDictionary>
The code behind of it is as follows (Snippet of code only)
public class NotifyIconViewModel
{
private Visibility visibility = Visibility.Collapsed;
public Visibility MFAVisibility
{
get
{
return ((1) == null ? Visibility.Collapsed : Visibility.Visible);
}
set
{
visibility = value;
}
}
}
There is other code in the code behind but that is irrelevant for this question.
I want to update the above property value from other class in the same project but I am not sure how can I get the instance of that class which is bound with the contextMenu.
And if I do try to set the MenuItem Visibility using code like below, it doesnt work;
public static void DisableMFAMenuitem()
{
System.Windows.Controls.ContextMenu ctxMenu = (System.Windows.Controls.ContextMenu)System.Windows.Application.Current.FindResource("SysTrayMenu");
System.Windows.Controls.ItemCollection items = ctxMenu.Items;
System.Windows.Controls.MenuItem itemtobeRemoved = null;
foreach (var item in items)
{
if (item.GetType() == typeof(System.Windows.Controls.MenuItem))
{
// do your work with the item
if (((System.Windows.Controls.MenuItem)item).Name == "MFA")
{
((System.Windows.Controls.MenuItem)item).Visibility = Visibility.Collapsed; // OR WHATEVER really
}
}
}
}
I think I am doing some small mistake in understanding, can anyone help here please?
Comment from Grx70 above helped.
I'm not sure I understand what you're trying to achieve here, but from
the first glimpse my guess would be that the troublemaker is the
x:Shared="False" attribute set on your resource, which means that each
FindResource("SysTrayMenu") call will yield a new ContextMenu instance
(so you're not modifying any pre-existing instance).
Related
I have a menu (with menuitems) in WPF. Unfortunately when I click on the menu heading it opens the menu to the right. The problem is that there is stuff on the right that I don't want it to overlap. How do I tell WPF to open the menu to the left? Do I need to do a control template? (control templates seem so heavy handed for such basic style changes).
Thanks!
KSG
While you can create a ControlTemplate to do this like they do here, I agree that it is a cumbersome method just to modify one value on a part of the MenuItems. Instead, I think that this is a great place to use an AttachedProperty. We can create something just like the ContextMenuService, but for Popups (In fact, I'm somewhat surprised that it isn't built in).
To change where the popup is opening, we're going to want to set the Popup's PlacementMode. We can use the propa shortcut to generate our AttachedProperty(or properties if you want to implement the rest). We need to add a callback to our PropertyMetadata, but if the AttachedProperty is set inline on the control in XAML then the callback will fire before the whole control is fully constructed. To ensure the MenuItem's template is applied, and the Popup exists before we try and set it's value, we can just attach to the Loaded event if it isn't already loaded.
Once it is loaded, we want to retrieve the Popup from the template, and if we look at the MenuItem class we can see that it has a TemplatePartAttribute defining the Popup's name as "PART_Popup". Once we have that, we can set the PlacementMode on the MenuItem's Popup.
public static PlacementMode GetMenuPlacement(DependencyObject obj)
{
return (PlacementMode)obj.GetValue(MenuPlacementProperty);
}
public static void SetMenuPlacement(DependencyObject obj, PlacementMode value)
{
obj.SetValue(MenuPlacementProperty, value);
}
// Using a DependencyProperty as the backing store for MenuPlacement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MenuPlacementProperty =
DependencyProperty.RegisterAttached("MenuPlacement",
typeof(PlacementMode),
typeof(Window1),
new FrameworkPropertyMetadata(PlacementMode.Bottom, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnMenuPlacementChanged)));
private static void OnMenuPlacementChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var menuItem = o as MenuItem;
if (menuItem != null)
{
if (menuItem.IsLoaded)
{
SetPopupPlacement(menuItem, (PlacementMode)e.NewValue);
}
else
{
menuItem.Loaded += new RoutedEventHandler((m, v) => SetPopupPlacement(menuItem, (PlacementMode)e.NewValue));
}
}
}
private static void SetPopupPlacement(MenuItem menuItem, PlacementMode placementMode)
{
Popup popup = menuItem.Template.FindName("PART_Popup", menuItem) as Popup;
if (popup != null)
{
popup.Placement = placementMode;
}
}
Now that we have our AttachedProperty, it's easy to change the Popup placement in the UI.
<Menu>
<MenuItem Header="Item 1"
local:Window1.MenuPlacement="Right">
<MenuItem Header="SubItem 1" />
<MenuItem Header="SubItem 2" />
<MenuItem Header="SubItem 3" />
<MenuItem Header="SubItem 4" />
</MenuItem>
<MenuItem Header="Item 2"
local:Window1.MenuPlacement="Left">
<MenuItem Header="SubItem 5" />
<MenuItem Header="SubItem 6" />
<MenuItem Header="SubItem 7" />
<MenuItem Header="SubItem 8" />
</MenuItem>
<MenuItem Header="Item 3"
local:Window1.MenuPlacement="Mouse">
<MenuItem Header="SubItem 9" />
<MenuItem Header="SubItem 10" />
<MenuItem Header="SubItem 11" />
<MenuItem Header="SubItem 12" />
</MenuItem>
</Menu>
i have a devexpress ListBoxEdit control with a context menu.
hear is my design`
<dxe:ListBoxEdit x:Name="lstEventsList" Grid.Column="1" Grid.Row="3" Tag="{Binding DataContext}" >
<mvvm:Interaction.Triggers>
<mvvm:EventToCommand EventName="SelectedIndexChanged" Command="{Binding GetReferenceCodeListOnEventSelect}" PassEventArgsToCommand="True" />
</mvvm:Interaction.Triggers>
<dxe:ListBoxEdit.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Command="{Binding SyncToMediaDevice}" Header="SYNC"
CommandParameter="{Binding}"/>
</ContextMenu>
</dxe:ListBoxEdit.ContextMenu>
</dxe:ListBoxEdit>
now problem is menu context command are not working..binding property is
public ICommand SyncToMediaDevice
{
get
{
return _syncToMediaDevice;
}
set
{
_syncToMediaDevice = value;
}
}`
Please help me thanks`
I have a problem with my small WPF tray icon which has a context menu assigned. If I do a right-click on the tray icon the context menu opens and you see a text box containing an integer value. Now when clicking to the "Create Instance" field the integer should increment by one. The new value should be shown in the textbox. On startup the correct inital value is shown in the textbox but changes during runtime are not reflected to the UI. I think there is a data binding problem... The click event is caught and even the value is incremented but the textbox does not recognize the new value...
I have no Main Window the application should only be a tray icon context menu.
App.xaml.cs
public partial class App : Application
{
// This objects are global
private TaskbarIcon notifyIcon;
private INotificationBarMessage message = null;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//create the notifyicon (a resource declared in NotifyIconResources.xaml)
notifyIcon = (TaskbarIcon) FindResource("Key_NotifyIcon");
notifyIcon.DataContext = this;
message = new NotificationBarMessage(notifyIcon);
message.Show(TextType.Startup);
}
}
ResourceContextMenu.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:local="clr-namespace:UserInterface.ViewModel"
x:Class="UserInterface.ViewModel.EventHandlerUI">
<ContextMenu x:Shared="false" x:Key="My_ContextMenu">
<ContextMenu.DataContext>
<local:ContextMenuModel /> <!-- reference to ContextMenuModel.cs -->
</ContextMenu.DataContext>
<!-- DataContext="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}} -->
<ContextMenu.Resources>
<local:ConverterBoolToVisibility x:Key="BoolToHiddenConverter"
TrueValue="Visible"
FalseValue="Hidden" />
<local:ConverterIntToString x:Key="IntToStringConverter" />
</ContextMenu.Resources>
<TextBlock Text="Status"/>
<Separator/>
<MenuItem Header="Create Instance"
MouseEnter="CreateInstance_OverEnter"
MouseLeave="CreateInstance_OverExit"
Click="CreateInstance_Click"
StaysOpenOnClick="True" />
<!-- Command="{Binding ShowWindowCommand}" -->
<MenuItem Header="Open Window"
StaysOpenOnClick="True"
Command="{Binding Commands.ShowWindowCommand}" />
<MenuItem Header="IP-Address"
Name="MenuItem_IPAddress"
Visibility="{Binding EventData.IsEnabled, Mode=TwoWay,
Converter={StaticResource BoolToHiddenConverter}}"
StaysOpenOnClick="True"/>
<TextBox Width="100"
Text="{Binding Path=EventData.Counter,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,
Converter={StaticResource IntToStringConverter}}"/>
<Separator/>
<MenuItem Header="Exit"
Command="{Binding Path=Commands.ExitApplicationCommand}" />
</ContextMenu>
<!-- Tray Icon -->
<!-- the application's NotifyIcon - started from App.xaml.cs.
Declares its own view model. -->
<tb:TaskbarIcon x:Key="Key_NotifyIcon"
x:Name="My_NotifyIcon"
IconSource="/View/gfx/_UserInterface.ico"
ToolTipText="tip"
ContextMenu="{StaticResource My_ContextMenu}"/>
App.xaml
<Application x:Class="UserInterface.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<!-- Note that this application does not have a StartupUri declared,
so no Window is automatically loaded.
Also, the ShutdownMode was set to explicit,
so we have to close the application programmatically. -->
<!-- merge NotifyIcon and related stuff into the application -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceContextMenu.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Here is the code where I fire the property changed event:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int _counter = 34;
public int Counter
{
get
{
return this._counter;
}
set
{
if (value != this._counter)
{
this._counter = value;
NotifyPropertyChanged();
}
}
}
Any help would be appreciated.
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>
I have a canvas and when a user right clicks on it, a context menu appears. I also have a checkbox, and when that box is checked, I DON'T want the context menu to appear. The reason for this is that, when the checkbox is checked, the first two right clicks from the user will drop ellipses at the two points of the right clicks. Right now though, the context menu will popup on those two right clicks. Here's the relative code:
<Window x:Class="Testproj.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Testproj"
xmlns:localConverters="clr-namespace:Testproj"
x:Name="this"
Height="650" Width="1091"
Loaded="this_Loaded"
Closing="this_Closing">
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="converter"/>
</Window.Resources>
<Grid Height="Auto">
<Grid.Resources>
<local:NullToVisibilityConverter x:Key="nullToVisibilityConverter" />
</Grid.Resources>
<Grid VerticalAlignment="Top">
<DockPanel>
<CheckBox x:Name="scaleBox" Content="Scale" IsChecked="False" Checked="scaleischecked"/>
</Menu>
</DockPanel>
</Grid>
<Viewbox Margin="0,23,0,157" x:Name="viewbox1" ClipToBounds="True">
<Canvas Margin="0,21,0,12" x:Name="canvas1" ClipToBounds="True" RenderOptions.BitmapScalingMode="HighQuality" MouseWheel="Canvas_Zoom" MouseRightButtonDown="get_MousePosition" HorizontalAlignment="Left" Width="3138" Height="1260">
<Canvas.RenderTransform>
<MatrixTransform x:Name="mt"/>
</Canvas.RenderTransform>
<Canvas.ContextMenu>
<ContextMenu Name="nodeContextMenu" Visibility="{StaticResource converter}" >
<MenuItem x:Name="test1" IsCheckable="False" Header="test1" Click="WaypointMenuItem_Click" >
</MenuItem>
<MenuItem x:Name="test2" IsCheckable="False" Header="test2" Click="KnownObjectMenuItem_Click" >
</MenuItem>
</ContextMenu>
</Canvas.ContextMenu>
</Canvas>
</Viewbox>
</Grid>
</Window>
and the code behind for the right-click on canvas:
private void get_MousePosition(object sender, MouseButtonEventArgs e)
{
if (scaleBox.IsChecked == true)
{
get_points(sender, e);
}
}
I've tried messing around with the isOpen property of the context-menu, but it always open on right click regardless if it's set to true or false.
Attempt at converter below. If this is correct, what is the proper way to bind the checkbox and contextmenu using this?
namespace Testproj
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility visibility = Visibility.Collapsed;
if (value != null)
{
visibility = (bool)value ? Visibility.Collapsed : Visibility.Visible;
}
return visibility;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I would implement a ValueConverter or MultiValueConverter and then bind to the checkbox using the converter to dictate the state (i.e. enabled/disabled) of the contextmenu.
<Canvas.ContextMenu>
<ContextMenu Name="contextmenu1" Visibility="{Binding ElementName=scaleBox, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" >
<MenuItem x:Name="item1" IsCheckable="False" Header="item2" />
<MenuItem x:Name="item2" IsCheckable="False" Header="item1" />
</ContextMenu>
Here's the way I figured out how to do it since I couldn't get the converter to work properly:
Set the ContextMenuService.IsEnabled property to false in the canvas. Then, in the code behind, set nodeContextMenu.IsOpen = true when the scalebox is not checked. This seems to do the trick.
<Canvas Margin="0,21,0,12" x:Name="canvas1" ContextMenuService.IsEnabled="False" />
if (scaleBox.IsChecked == true)
{
get_Scaling(sender, e);
}
else
{
nodeContextMenu.IsOpen = true;
}