0
votes

i am trying to bind the context menu (with checkbox) of tab to observable collection. When user checks or uncheks the menuitem for the first time, that state is reflected in associated bool variable in obesarvable collection. But after that it not reflected. Binding in XAML looks like this :

        <TabItem.ContextMenu>
            <ContextMenu Name="menu"
                         ItemsSource="{Binding Path=FieldNameCollection,Mode=TwoWay}"
                         ItemTemplate="{StaticResource SelectIndexFieldMenu}"></ContextMenu>
        </TabItem.ContextMenu>

Data Template is

        <DataTemplate x:Key="SelectIndexFieldMenu">
            <MenuItem Header="{Binding Path=IndexFieldName}"
                      IsCheckable="True"
                      IsChecked="{Binding Path=isIndexFieldSelected,Mode=TwoWay}"
                      IsEnabled="{Binding  Path=isCheckBoxEnabled}" />
        </DataTemplate>

(i am not able to add code snippet, so i removed '<' :( ) The class for observable collection is derived from NotifierBase. Another thing i noticed is if I check the context menu's itemsource in view.xaml.cs at ContextMenuClosing, the states are correctly reflected.

1
Do you implement INotifyPropertyChanged interface in your class?decyclone
Yes, I have implemented INotifyProperyChanged. Thx for adding code properly (how did u do that?)Rik
please paste the relevant code from presenter also, and if possible, paste also bigger portion of your xaml. I'm what is the DataContext TabControl.so paste the TabControl xaml.Nawaz
@Nawaz, datacontext for tab is combination of some variables & collection & they all are including this observable collection are part of ViewModel Class for this View.Rik
Just stumbled over this old question - it's not clear from the question what the properties are bound to, but my current other problem could be solved by binding to the PlacementTarget.DataContext of the parent ContextMenu: {Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}mattanja

1 Answers

0
votes

It's not clear without seeing more code what's causing the properties not to update but there are a few issues that may be contributing.

The "isIndexFieldSelected" and "isCheckBoxEnabled" values look like field names rather than properties. If that's the case that would cause the problem since Binding requires properties but given the posted code it's not clear.

The way you're templating the menu items will cause two MenuItem objects to be created for each collection item. ContextMenu automatically generates a MenuItem instance for each item in the bound ItemsSource collection into which the DataTemplate for each item is injected. By declaring a MenuItem inside the ItemTemplate you are creating a MenuItem inside the Header section of each MenuItem in the ContextMenu. It may be the case that you are clicking on, and checking, the outer MenuItem which is not bound to the data. Try using these resources instead to both template and style the MenuItems that are generated for you:

<DataTemplate x:Key="SelectIndexFieldMenuTemplate">
    <TextBlock Text="{Binding Path=IndexFieldName}"/>
</DataTemplate>

<Style x:Key="SelectIndexFieldMenuStyle" TargetType="{x:Type MenuItem}">
    <Setter Property="IsCheckable" Value="True" />
    <!--IsChecked is already TwoWay by default-->
    <Setter Property="IsChecked" Value="{Binding Path=isIndexFieldSelected}" />
    <Setter Property="IsEnabled" Value="{Binding  Path=isCheckBoxEnabled}" />
</Style>

And use them like this:

<TabItem.ContextMenu>
    <!--TwoWay doesn't ever do anything on ItemsSource-->
    <ContextMenu Name="menu" ItemsSource="{Binding Path=FieldNameCollection}"
                 ItemContainerStyle="{StaticResource SelectIndexFieldMenuStyle}"
                 ItemTemplate="{StaticResource SelectIndexFieldMenuTemplate}"/>
</TabItem.ContextMenu>

It's also possible that your bound properties are not using INotifyPropertyChanged correctly, which would cause the UI to not update when the menu item checked state. It should look something like this:

private bool _isIndexFieldSelected;
public bool isIndexFieldSelected
{
    get { return _isIndexFieldSelected; }
    set
    {
        if (_isIndexFieldSelected == value)
            return;
        _isIndexFieldSelected = value;
        NotifyPropertyChanged("isIndexFieldSelected");
    }
}

public virtual void NotifyPropertyChanged(string propertyName)
{
    PropertyChangedEventArgs ea = new PropertyChangedEventArgs(propertyName);
    if (PropertyChanged != null)
        PropertyChanged(this, ea);
}

public event PropertyChangedEventHandler PropertyChanged;