Firing context menu from user control does not work - c#

I try to use a context menu from a user control's list view but the command is not firing (neither enabling/disabling when needed).
Code:
<UserControl ....
<UserControl.Resources>
<ContextMenu x:Key="SharedInstanceContextMenu">
<MenuItem Header="Edit" Command="{Binding ElementName=UC, Path=DataContext.EditSelectedItemCommand}" CommandParameter="{Binding}"/>
</ContextMenu>
<Grid ...>
<ListView ....>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected}"/>
<Setter Property="ContextMenu" Value="{StaticResource SharedInstanceContextMenu}"/>
</Style>
</ListView.ItemContainerStyle>
How can I make the command firing (and enabling/disabling, part of the command behavior)?
(btw, this questions seems similar to Treeview context menu command not firing but after trying all solutions there it still does not work.)

Does your output window contain binding errors complaining the command doesn't exist on your view model? If so, it probably means that your ContextMenu's DataContext isn't set correctly. Context menus are not part of the visual tree because they need to pop up on top of elements which means they don't inherit their DataContext the way other controls do. One solution is to use the PlacementTarget to access your view model - see this post for more information.

Related

Binding the Setter Value in a Style to the main model

i want to write a WPF-Application that shows different pages/scenes. So, I have a ViewModel (MainViewModel) that provides a list of scenes (SceneViewModel). Every scene has a name which can be accessed by a property SceneName.
I create the MainViewModel in Window.DataContext:
<Window.DataContext>
<!-- Declaratively create an instance of the main model -->
<models:MainViewModel />
</Window.DataContext>
I then want a menu-item that lists all scenes. When one of the menu-items is clicked, the scene should change. Therefor i created an Command in the MainViewMode: ChangeSceneCommand.
In XAML I want to create the menu-list in the following way:
<Menu Grid.Row="0">
<Menu.Resources>
<Style x:Key="SetSceneCommandItem" TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding SceneName}"/>
<Setter Property="Command" Value="{Binding SetSceneCommand}"/> <-- Here is the problem
<Setter Property="IsChecked" Value="False" />
</Style>
</Menu.Resources>
<MenuItem Header="Scenes" ItemsSource="{Binding Scenes}" <-- Scenes is a list with scenes^^
ItemContainerStyle="{StaticResource SetSceneCommandItem}" /> <-- Here the style is set
</Menu>
The Item-Header binds well but the "SetSceneCommand" can not be found, because wpf tries to find the "SetSceneCommand"-property in the SceneViewModel. How can i say wpf to access the model in the datacontext out of the style?
PS: You may have noticed that SetSceneCommand will need a scene as parameter to work, but I wanted to implement that later.
You can use RelativeSource. If SetSceneCommand is part of the same context used by Menu then it will look like this:
<Setter
Property="Command"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type Menu}}, Path=DataContext.SetSceneCommand}"/>
this tells Binding to go up the visual tree until Menu and take DataContext.SetSceneCommand from there

Using commands with MenuItem's in WPF

So I have this MenuItem which is using a list of CultureInfos as an itemsource.
What I'm trying to do is to fire a function when a CultureInfo is clicked/selected, which is supposed to change the localization of the application to the selected cultureinfo.
I can safely say that the function is working as it should.
After researching and trying a few examples, this is what I ended up with, which unfortunately doesn't work:
<MenuItem Header="{lex:LocText MenuLanguages}" ItemsSource="{Binding LanguageList}" DisplayMemberPath="Name">
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Command" Value="{Binding SetLanguage}" />
<Setter Property="MenuItem.CommandParameter" Value="{Binding}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
The command:
private ICommand _SetLanguage;
public ICommand SetLanguage
{
get
{
if (_SetLanguage == null)
_SetLanguage = new RelayCommand(ChangeLanguage);
return _SetLanguage;
}
}
public void ChangeLanguage(object langChosen)
{
LocalizeDictionary.Instance.Culture = CultureInfo.GetCultureInfo(langChosen.ToString());
}
CultureInfo.GetCultureInfo() takes string as a parameter.
The itemsource is basically an ObservableCollection<CultureInfo>.
My question is what could be wrong with the above code? I have been trying quite a few 'solutions' but nothing really worked...
When I select an item form the list nothing happens at all.
*I also tried to set a breakpoint on the ChangeLanguage method, which brought me to a conclusion that the method never even fires.
Using caliburn.micro and WPFLocalizationExtension extension.
If it doesn't work, then the binding is wrong. Check out for binding errors in debug window.
You need to use relativesource, since binding directly wont do what you think will do.
<MenuItem Header="_Recent files" ItemsSource="{Binding RecentFiles, Converter={StaticResource RecentFilesToListOfStringsConverter}, Mode=OneWay}" >
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding DataContext.ImportRecentItemCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type MenuItem}, AncestorLevel=1}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
A Menu has a different LogicalTree than the rest of the Markup. For this Reason you need to search for the right DataContext first as Erti-Chris suggested.
Also every DataTemplate has the DataContext of the Type T which is part of the List of the bound ItemsSource.

MVVM Set MenuItem's DataContext

I have a ListView with an ItemSource from a List of string.
Now I have added a context menu which should just implement some commands. But the problem ist how to set the DataContext. Found some solutions but none of these worked for me. Dont know where my fault ist.
Here my XAML code, reduced to the important regions.
<ListView x:Name="lstBackups" ItemsSource="{Binding SelectedClient.Backups}">
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Do Something" DataContext="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}}"
cinch:SingleEventCommand.RoutedEventName="MouseLeftButtonUp"
cinch:SingleEventCommand.TheCommandToRun="{Binding Path=DataContext.OpenBackupInExplorerCommand, ElementName=UserControl}">
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
I'm sure you've noticed that the ContextMenu is not part of the same visual tree as your user control (annoying I know). So you have to get a bit creative with your binding logic.
Try changing the command binding to the following
cinch:SingleEventCommand.TheCommandToRun="{BindingPath=PlacementTarget.DataContext.OpenBackupInExplorerCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ContextMenu}}}"
That should attempt to get the DataContext of the placement target (in your case the ListView) which should inherit the DataContext of the UserControl
Hopefully that will work.

WPF context menu doesn't stay open

In WPF I am trying to put a context menu on the items of a listbox. When I run my app and right click on an item of the listbox the menu pops up for a split second and then closes again. I just can't figure out what I am doing wrong.
This is the code I am using:
<ListBox Grid.Column="0" Name="lsbAddedElements" Width="150" Margin="3,3,3,3"
SelectionMode="Multiple">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Delete" Click="btnDeleteElement_Click"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
The listbox is bound to an ObservableCollection in code when the window is initialised, so item management is taken care of in code behind.
UPDATE:
I might need to add that thsi is part of an adin I am making for Excel. I am connecting to Excel using ExcelDNA then passsing the handle on to the WPF window that this code snippet is part of.
Could this be a reason for the context menu behaving in an unexpected way?
I think the problem is that the listbox item is getting focused. A simple solution to your problem is to set the context menu on the list box and enable/disable context menu items if the list box has a selected item.

Loading UserControl to the region of the Window on ComboBox change

I have got ComboBox which is populated with collection of customTypes. On comboBox change, I would like to load/change content in the particular region so that it loads related data for the selected ComboBox item (it could be in the form of loading userControl or I i dont mind specifying DataTemplate for it).
It is similar to this question WPF Load Control question. But in this question, he is talking about individual DataTemplates in the actual Listbox, while I am talking about populating certain window region on ComboBox change.
I am using MVVM (and not PRISM) .Net 3.5.
U could use ContentControl which is the placeholder for the actual Content that is dynamically decided as per combobox selection.
The follwoing code is just for guidance
<Window ...>
<Window.Resources>
<MyView1 x:Key="MyView1" />
<MyView2 x:Key="MyView2" />
</Window.Resources>
...
<ComboBox x:Name="MyCombo">
<ComboBox.ItemsSource>
<sys:String>"MyView1"</sys:String>
<sys:String>"MyView2"</sys:String>
....
</ComboBox.ItemsSource>
</ComboBox>
...
<!-- This is where your region is loaded -->
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=SelectedItem,
ElementName=MyCombo}"
Value="MyView1">
<Setter Property="Content"
Value="{StaticResource MyView1}"
</DataTrigger>
<DataTrigger Binding="{Binding Path=SelectedItem,
ElementName=MyCombo}"
Value="MyView2">
<Setter Property="Content"
Value="{StaticResource MyView2}"
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Window>
The data loading can be part of the MyView1 and MyView2 user control's constructor or your main UI's data context view model.
As far as I understand the question is how to change underlying data being bound to UI and not a DataTemplate only.
You can use EventSetter which will be handled in code behind where you can switch DataContext for a region you've mentioned:
<ComboBox>
<ComboBox.Resources>
<Style TargetType="ComboBoxItem">
<EventSetter Event="Selector.SelectionChanged"
Handler="YourHandler"/>
</Style>
</ComboBox.Resources>
</ComboBox>
But from MVVM perspectives it could be not perfect solution so you can introduce your own ComboBox class wich is Command aware, see this SO post: WPF command support in ComboBox
In this way you can decouple logic from UI using Command.

Categories

Resources