Home > Mobile >  Issues Binding ContextMenu to ItemsSource
Issues Binding ContextMenu to ItemsSource

Time:09-10

I want to bind my ListView's ContextMenu to an ItemSource 'GetContextMenu' specified in the ViewModel which the entire UserControl is using for it's DataContext. I have tried specifying it in multiple different ways, including using the RelativeSource and currently trying to bind by name to either the ClientsListView or ClientsTab. All which I have tried failed. The specific error I am getting is:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=ClientsListView'. BindingExpression:Path=DataContext.GetContextMenu; DataItem=null; target element is 'ContextMenu' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')

It's worth mentioning that my binding for the SelectionChanged event that you'll see below in the XAML works just fine, so I really have no clue what's going on.

<UserControl x:Class="ServerUI.Views.MainWindowViews.ClientsTabView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800"
             Name="ClientsTab">
    <Grid>
        <ListView x:Name="ClientsListView" ItemsSource="{Binding ClientViewModels}">
            <ListView.ContextMenu>
                <ContextMenu ItemsSource="{Binding ElementName=ClientsListView, Path=DataContext.GetContextMenu}"/>
            </ListView.ContextMenu>
            <ListView.View>
                <GridView>
                    <GridViewColumn x:Name="OnlineStatusHeader" Header="Online Status" DisplayMemberBinding="{Binding Online}" />
                    <GridViewColumn x:Name="NameHeader" Header="Computer/User" DisplayMemberBinding="{Binding ComputerUser}" />
                </GridView>
            </ListView.View>
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding UpdateSelectedClientsCommand}" CommandParameter="{Binding ElementName=ClientsListView, Path=SelectedItems}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ListView>
    </Grid>
</UserControl>
namespace ServerUI.ViewModels.MainWindowViewModels
{
    public class ClientsTabViewModel : ObservableObject
    {
        public ObservableCollection<ClientViewModel> ClientViewModels { get; } = new();
        public IEnumerable<ClientViewModel> SelectedClients { get; set; }
        

        public ICommand CloseConnectionCommand
            => new RelayCommand(() => ExecuteCloseConnectionCommand());

        public ICommand ConfigureClientCommand
            => new RelayCommand(() => ExecuteConfigureClientCommand());

        public ICommand UpdateSelectedClientsCommand
            => new RelayCommand<object>(e => ExecuteUpdateSelectedClientsCommand(e));

        public ICommand OpenServerModuleCommand
            => new RelayCommand<object>(e => ExecuteOpenServerModuleCommand(e));

        public List<FrameworkElement> GetContextMenu
        {
            get
            {
                List<FrameworkElement> menuItems = new();

                menuItems.Add(new MenuItem() { Header = "Configure Client", Command = ConfigureClientCommand });
                menuItems.Add(new MenuItem() { Header = "Close Connection", Command = CloseConnectionCommand });
                menuItems.Add(new Separator());

                foreach(var client in SelectedClients)
                {
                    foreach(var module in client.Client.LoadedServerModules)
                    {
                        menuItems.Add(new MenuItem() { Header = module.ModuleName, Command = OpenServerModuleCommand, CommandParameter = module });
                    }
                }

                return menuItems;
            }
        }

        void ExecuteUpdateSelectedClientsCommand(object param)
        {
            System.Collections.IList items = (System.Collections.IList)param;
            SelectedClients = items.Cast<ClientViewModel>();
        }

CodePudding user response:

You can try like this:

<ListView Tag="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
    <ListView.ContextMenu>
        <ContextMenu
            DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"
            ItemsSource="{Binding GetContextMenu}"
            />
    </ListView.ContextMenu>
</ListView>
  • Related