Can't access datacontext of parent

2019-09-17 02:56发布

问题:

Basically what i have is a ListBox with ContextMenu

 <ListBox  Margin="2,0,0,0"  Grid.Row="1" ItemsSource="{Binding MyCollection}">
        <ListBox.ItemTemplate>
                <DataTemplate>
                    <Button  Style="{StaticResource NoVisualButton }" Tag="{Binding ID}" Width="430" toolkit:TiltEffect.IsTiltEnabled="True"  Margin="0,0,0,12" Click="OnSelectWorkOutItemClick">
                        <StackPanel>
                            <toolkit:ContextMenuService.ContextMenu>
                                <toolkit:ContextMenu>
                                    <toolkit:MenuItem Header="delete" Tag="{Binding ID}" Click="onContextMenuDeleteItemClick" IsEnabled="{Binding IsDeleteOptionEnable, ElementName=LayoutRoot}"/>
                                    <toolkit:MenuItem Header="edit"  Tag="{Binding ID}" Click="onContextMenuItemEditClick" />
                                </toolkit:ContextMenu>
                            </toolkit:ContextMenuService.ContextMenu>
                            ...
                        </StackPanel>
                    </Button>
                </DataTemplate>
       </ListBox.ItemTemplate>
 </ListBox>

So if MyCollection has only one item, i have to disable delete MenuItem.

My model has a property

   public bool IsDeleteOptionEnable
       {             
           get
           {
               return MyCollection.Count() >= 2;
           }
       }

In the page i am setting the DataContext like:

   protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (IsDataLoaded)
            {
                this.DataContext =MyModel;
            }           
        }

The listbox is getting populated, but i can't disable "delete" MenuItem. What am i doing wrong?

回答1:

Try

  IsEnabled="{Binding DataContext.IsDeleteOptionEnable, ElementName=LayoutRoot}"


回答2:

Since the IsDeleteOptionEnable is a regular property, your view won't get notified when the property is changed. On options would be implementing INotifyPropertyChanged in your model (actually that should be ViewModel in an MVVM pattern) and calling the PropertyChanged event whenever items in your collection gets changed.

class YourModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;
    ..
    ..
    public YourModel() {
        this.MyCollection = ...;
        this.MyCollection.CollectionChanged += MyCollection_CollectionChanged;
    }
    public bool IsDeleteOptionEnable {             
       get {
           return MyCollection.Count() >= 2;
        }
    }
    private void MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
         this.OnPropertyChanged("IsDeleteOptionEnable");
    }
    private void OnPropertyChanged(string name = null) {
         if (this.PropertyChanged != null) {
            PropertyChangedEventArgs ea = new PropertyChangedEventArgs(name);
            this.PropertyChanged(this, ea);
         }
     }
}

Now when an item get removed or added to the collection, the model raises and PropertyChanged event so that the view will be aware that the IsDeleteOptionEnable property is (actually might) changed, and the enabled state of the button gets updated.



回答3:

As DataSource you need to use ObservableCollection. Then you need to implement INotifyPropertyChanged -interface in the class which contains the binded Property.

Example Class:

// Example of binded object
public class MyItem: INotifyPropertyChanged {

   // Binded Property
   private String itemIsVisible = "Yes";
   public String ItemIsVisible{
      get { return itemIsVisible; }
      set {
         itemIsVisible = value;

         // This ensures the updating
         OnPropertyChanged("ItemIsVisible");
      }
   }

   protected void OnPropertyChanged(string name) {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null) {
         handler(this, new PropertyChangedEventArgs(name));
      }
   }
}

Example XAML:

<TextBlock Text="{Binding ItemIsVisible}" />