0

My goal is to disable/collapse a menuitem if the user does not have the rights to it. The binding i'm looking for is in my ViewModel as a boolean. I know that it's trying to find the property "IsAdmin" inside of the property "InstructionsUpdates". I just can't find a way to make the menuitem use the datacontext of the window.

Viewmodel:

 Public Property IsAdmin As Boolean
    Get
        Return _IsAdmin
    End Get
    Set
        SetValue(_IsAdmin, Value)
    End Set
End Property

Public Property InstructionsUpdates As ObservableCollection(Of ClsInstruction)
    Get
        Return _InstructionsUpdates
    End Get
    Set
        SetValue(_InstructionsUpdates, Value)
    End Set
End Property

Public Class ClsInstruction
    Public FileName As String = ""
    Public Property Name As String = ""
    Public Property IsChecked As Boolean = False
    Sub New(nName, nFileName)
        Name = nName
        FileName = nFileName
    End Sub
End Class

Public Sub New()
    IsAdmin = False
End Sub

XAML:

<ItemsControl x:Name="InstructionsItemControl"  ItemsSource="{Binding InstructionsUpdates}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <UniformGrid Columns="2" ScrollViewer.CanContentScroll="True"/>
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                            <StackPanel.ContextMenu>
                                                <ContextMenu>
                                                    <MenuItem x:Name="MnuViewInstruction"
                                                              Click="MnuViewInstruction_Click"
                                                              Header="Preview">
                                                        <MenuItem.Icon>
                                                            <iconPacks:PackIconMaterialDesign Kind="Pageview"/>
                                                        </MenuItem.Icon>
                                                    </MenuItem>
                                                    <MenuItem x:Name="MnuEdit"
                                                              Click="MnuEdit_Click"
                                                              Header="Edit (Binding not working)"
                                                              IsEnabled="{Binding IsAdmin}">
                                                        <MenuItem.Icon>
                                                            <iconPacks:PackIconMaterial Kind="FileEdit" />
                                                        </MenuItem.Icon>
                                                    </MenuItem>
                                                </ContextMenu>
                                            </StackPanel.ContextMenu>
                                            <CheckBox IsChecked="{Binding IsChecked}"/>
                                            <Label Content="{Binding Name}"/>
                                        </StackPanel>
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>

I've tried:

IsEnabled="{Binding IsAdmin, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">

And:

 IsEnabled="{Binding DataContext.IsAdmin, ElementName=MainWindow1}">

"MainWindow1" being the x:Name I gave to my window to test it out I've also tried using a window.ressource and then putting it inside my stackpanel, but turns out bindings don't work inside a ressource (form what I've seen)

  • The correct binding should be `IsEnabled="{Binding DataContext.IsAdmin, ElementName=MainWindow1}">` since MainWindow1 doesn't have a property named `IsAdmin` but its DataContext (the viewModel) does. – Ostas Feb 17 '22 at 19:21
  • You are correct, but that does not solve my problem. It seems that there is something keeping the contextmenu from having access to other sources. I've got no clue. This is the only binding that is not working so I know that It's something very specific that has to do with the itemcontrol and its datatemplate. – Anthony Côté Feb 17 '22 at 19:31
  • My bad, I believe ContextMenu are in a different visual tree. I don't have time to make an answer but check this one : https://stackoverflow.com/a/35441736/13448212 – Ostas Feb 17 '22 at 19:35
  • No success. Could it be that I'm using a UniformGrid as the paneltemplate? – Anthony Côté Feb 17 '22 at 20:36

1 Answers1

0

This will work, this is a bit tricky since neither DataTemplate not ContextMenu elements can use ElementName

<ItemsControl x:Name="InstructionsItemControl"  ItemsSource="{Binding InstructionsUpdates}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="2" ScrollViewer.CanContentScroll="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!--The Tag property of the StackPanel will contain the DataContext of the Window (the viewModel)-->
                <StackPanel Orientation="Horizontal" Background="Green" Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=DataContext}">
                    <StackPanel.ContextMenu>
                        <!--The Tag of the element posessing the ContextMenu is retrieved and stored in the Tag property of the ContextMenu-->
                        <ContextMenu Tag="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=Self}}">
                            <MenuItem x:Name="MnuViewInstruction"
                                                          Header="Preview">
                            </MenuItem>
                            <!--The Tag property of the contextMenu contains a reference to the viewModel of the window-->
                            <MenuItem x:Name="MnuEdit"
                                                          Header="Edit (Binding not working)"
                                                          IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}, Path=Tag.IsAdmin}">
                            </MenuItem>
                        </ContextMenu>
                    </StackPanel.ContextMenu>
                    <CheckBox IsChecked="{Binding IsChecked}"/>
                    <Label Content="{Binding Name}"/>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

Related answers : Binding ElementName inside a DataTemplate and WPF Databinding ContextMenu of Button inside a DataTemplate inside an ItemsControl

Ostas
  • 839
  • 7
  • 11