I have an ObservableCollection in my ViewModel and I want to create a ContextMenu which is bindded to that collection where every item in the collection has a submenu and all submenus are the same.
For example the collection is {10,20,30} and the submenu is
- Param (MenuItem)
- Set (MenuItem)
- Reset (MenuItem)
- Clear (MenuItem)
so that the final context menu would look something like this\
- 10
- Param
- Set
- Reset
- Clear
- 20
- Param
- Set
- Reset
- Clear
- 30
....
I've tried creating a resource
<x:Array x:Key="MenuResource" Type=Control>
<MenuItem Header="Param"/>
<MenuItem Header="Set"/>
<MenuItem Header="Reset"/>
<MenuItem Header="Clear"/>
</x:Array>
and setting to ItemSource Property in MenuItem Style of the ItemContainerStyle of the ContextMenu.
Nothing seems to work.
Can someone please show me the XAML way to do this.
Thanks
You have to define HierarchicalDataTemplate to bind child collection and directly bind outer collection to ItemsSource of Context menu like this:
<TextBlock Text="Context menu test">
<TextBlock.ContextMenu>
<ContextMenu ItemsSource="{Binding YourCollection}">
<ContextMenu.ItemTemplate>
<HierarchicalDataTemplate
ItemsSource="{Binding ChildCollection}">
<TextBlock Text="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
Assuming Name is a property in your underlying source object.
Related
I have a list of strings that holds the names of menu items:
List<string> namesStorage;
How do I bind this list as collection in XAML?
Right now I have wrote this is part, which already works:
<StackPanel Orientation="Vertical">
<MenuItem Header="MenuItem1" Command="{Binding Command1}" />
<MenuItem Header="MenuItem2" Command="{Binding Command1}" />
</StackPanel>
This items must have one command (different arguments will be set in the view model).
But I think this is not a good way to set every MenuItem in XAML - It is ok now for two items but I wonder how to make a universal decision for any number of this menu items. I have created a list that holds names but how to bind it (and keep a commands)?
After setting the correct DataContext, this should work:
<ItemsControl ItemsSource="{Binding namesStorage}" x:Name="ItemsControlName">
<ItemsControl.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}" Command="{Binding ElementName=ItemsControlName, Path=DataContext.Command1}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Edit: Removed Parent-Stackpanel as suggested in the comments
I am having problems binding a textbox to my viewmodel.
<DataTemplate x:Key="ContentDetail" >
<StackPanel Orientation="Horizontal" Height="500"">
<TextBlock TextWrapping="Wrap" Text="{Binding SelectedCall.CUCODE }" />
</StackPanel>
</DataTemplate>
I know the binding is fine as I have it also bound outside the datatemplate
DataContext="{Binding HelpdeskViewModel, Source={StaticResource ServiceLocator}}"
dx:ThemeManager.ThemeName="VS2010" SelectedItem="{Binding SelectedCall,UpdateSourceTrigger=PropertyChanged}">
Any pointers would be gratefully accepted.
Edit:
<dxg:GridControl.DetailDescriptor>
<dxg:TabViewDetailDescriptor>
<dxg:TabViewDetailDescriptor.DetailDescriptors>
<dxg:ContentDetailDescriptor ContentTemplate="{StaticResource ContentDetail}" HeaderContent="More Detail" >
</dxg:ContentDetailDescriptor>
</dxg:TabViewDetailDescriptor.DetailDescriptors>
</dxg:TabViewDetailDescriptor>
</dxg:GridControl.DetailDescriptor>
Items within a Template are bound to the current item in the Template (so your datacontext in this scope isn't your window's viewmodel, but the current item).
I assume SelectedCall is a property on your window's viewmodel and not a property on each bound item, so you can't access that. If it's also a property of each model then simply bind to CUCODE, else if it's a single per window item, you'd have to trace back to the ancestor window & bind to the datacontext of the window instead of the one automatically set for you within the context of the Template.
You're probably looking for something like that
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=SelectedCall.CUCODE }}" />
how do I create treeview like this one:
<TreeViewItem Header="Customers" ItemsSource="{Binding Customers}">
Customers
Anna
Delete
Open
Peter
Delete
Open
Andrew
Delete
Open
I would like to create child item template something like this
<TreeViewItem Header="{Binding Header}">
<TreeViewItem Header="Delete"/>
<TreeViewItem Header="Open"/>
</TreeViewItem>
But it does not quite work that well because I end up having treeviewitem with datatemplate treeviewitem, but I would like to override controltemplate of child elements, but not parent.
Sure, I want to avoid my binding to be TreeViewItem, nor I want to create children with those static obejct "Open", "Delete".
Here is one of the best articles about TreeView I ever read.
Inside TreeView.Resources you could declare several DataTemplates with different DataType if Delete and Open commands were items of some collection. (TargetType for the commands would be ICommand).
But it seems to mee you do not need TreeView at all.
Customers is a header of the list. If you want it to be epxpandable use Expander control.
Then it is sufficient to provide one data template for each customer.
<DataTemplate DataType="CustomerTypeName">
<Expander Header="{Binding CustomerName}">
<Button Command="{Binding DeleteCustomerCmd}" Content="Delete" Margin="15,0,0,0"/>
<Button Command="{Binding OpenCustomerCmd}" Content="Open" Margin="15,0,0,0"/>
<Expander/>
<DataTemplate>
But here you'll have some troubles with selection highlight.
public class CommandWrapper
{
ICommand Command {get;set;}
string CommandName {get;set;}
}
public class CustomerViewModel
{
Customer Customer {get;set;}
IEnumerable<CommandWrapper> Commands {get;}
}
Let Customers be collection of CustomerViewModel.
Then the following XAML can help:
<TreeView ItemsSource="{Binding ...}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="TypeHoldingCustomersCollection"
ItemsSource="{Binding Customers}">
<TextBlock Text="Customers"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="CustomerViewModel"
ItemsSource="{Binding Commands}">
<TextBlock Text="{Binding Path=Customer.Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="CommandWrapper">
<Button Content="{Binding CommandName}" Command="{Binding Command}"/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
I'm wondering how to pass the selected item to a command from a treeview / HierarchicalDataTemplate ?
Here is the code that I have so far, it displays the context menu but I haven't bound the commands to it yet. The command binding is the easy part, but how do I tell which node it came from ?
<HierarchicalDataTemplate
DataType="{x:Type viewModel:UsersViewModel}"
ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0" Source="Images\Region.png" />
<TextBlock Text="{Binding UserName}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Edit" />
<MenuItem Header="Delete"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
Just {Binding} should be the whole item.
(To pass it to the Command bind the CommandParameter, in Execute and CanExecute it will become the method parameter (which you then need to cast to your item-type))
I am using an ObjectDataProvider and a DataTemplate to populate a MenuItem inside my Menu bar. (WPF, C#/XAML) See snipet below.
Result: The top menu item appears, when i click on it, the wrapping menu item (the one with the bound header text) appears along with the little arrow indicating the presence of children but hovering or clicking the arrow does not show the children, they cannot be accessed.
Expected result: The children are visible and behave properly.
Snippet:
<ObjectDataProvider x:Key="Brokers" ObjectInstance="{x:Static brokers:BrokerManager.Instance}" MethodName="GetBrokers" IsAsynchronous="True" />
<DataTemplate x:Key="BrokerMenuItem" DataType="IBroker">
<MenuItem Header="{Binding Path=Name}">
<MenuItem Header="Connect" />
<MenuItem Header="Disconnect" />
</MenuItem>
</DataTemplate>
<MenuItem Header="Brokers" ItemsSource="{Binding Source={StaticResource Brokers}}" ItemTemplate="{DynamicResource BrokerMenuItem}"/>
arsenmrkt: I have exactly the same problem, if I populate a MenuItem using a DataTemplate I cant seem to add children to any of those generated items. I don't understand your answer though, how should I use the ContentPresenter to get around this problem?
EDIT:
Actually, my problem was'nt exactly the same, since I'm trying to bind a collection of collections to a menu. I think I've gotten it to work though using the HierarchicalDataTemplate:
<Menu>
<MenuItem Header="{Binding Name}" ItemsSource="{Binding MenuOptions}">
<MenuItem.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Categories}">
<MenuItem Header="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Name}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</Menu>
Does this help you NicholasF?
After searching for over a week, i finally found how to make this work properly. It turns out DataTemplates don't work too great for dynamic menus. The proper way to do this is to use the ItemContainerStyle property of MenuItem. (Or is that ItemStyleContainer?)
Simply create a style to override the header and set it to whatever you need. I them overrode the ItemsSource to include my children. However be careful here, as the children will inherit the style and each have the same children and generate a recursive menu. You'll need to override the ItemsSource of your children and set it to an empty x:Array or the likes.
There are several blogs out there describing how to use ItemContainerStyle, check them out.
ItemSource property of menuitem control is used for giving childes for that item, try to use <ContentPresenter /> with that datatemplate.