0

I'm wondering how do I set the bindings to a public variable within my Viewmodel WorkTabViewModel. I set two examples I tried below,

The Foreground="{Binding MenuItemForeground}" and

Foreground="{Binding MenuItemForeground, RelativeSource={RelativeSource AncestorType=UserControl}}"

But they both don't recognize MenuItemForeground.

<TextBlock VerticalAlignment="Center" FontWeight="Bold" Margin="1 0 0 0" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}" >
    <TextBlock.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Close tab" cal:Message.Attach="[Click] = [CloseTab()]" />
            <MenuItem Header="Close other tabs" cal:Message.Attach="[Click] = [CloseOtherTabs()]" IsEnabled="False" Foreground="{Binding MenuItemForeground, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
            <MenuItem Header="Close all tabs" cal:Message.Attach="[Click] = [CloseAllTabs()]" IsEnabled="False" Foreground="{Binding MenuItemForeground}"/>
         </ContextMenu>
    </TextBlock.ContextMenu>
</TextBlock>

WorkTabViewModel

public Brush MenuItemForeground { get; set; }
public void CloseTab(){...}
public void CloseOtherTab(){...}
public void CloseAllTabs(){...}
Master
  • 2,038
  • 2
  • 27
  • 77
  • In case the parent DataContext is actually set to an instance of WorkTabViewModel, and the MenuItemForeground property has a value, the expression `Foreground="{Binding MenuItemForeground}"` should work. The second attempt is wrong. Also, `DataContext="{Binding Path=DataContext, ...}"` on the TextBlock is redundant, as the parent DataContext is inherited to child element. – Clemens Feb 04 '15 at 19:11
  • Hi Clemens, when I set MenuItemForeground, it says Cannot resolve property "menuitemforground" in data context of type "object". It points to WorkTabViewModel and works because it fires closetab() and the other functions. – Master Feb 04 '15 at 19:23
  • Try. Foreground="{Binding DataContext.MenuItemForeground, RelativeSource={RelativeSource AncestorType=UserControl}}" – Ayyappan Subramanian Feb 04 '15 at 19:39

1 Answers1

1

A context menu is not a part of the visual tree so it's not inheriting the parent controls DataContext. You also can't use the ancestor syntax because of this.

One solution is to use a binding proxy.

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Data.
    // This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data",
                                    typeof(object),
                                    typeof(BindingProxy),
                                    new UIPropertyMetadata(null));
}

And it's usage in XAML.

<TextBlock VerticalAlignment="Center" 
           FontWeight="Bold" 
           Margin="1 0 0 0"
           DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}">
    <TextBlock.Resources>
        <helper:BindingProxy x:Key="proxy"
                             Data="{Binding }" />
    </TextBlock.Resources>
    <TextBlock.ContextMenu>
        <MenuItem Header="Close tab" 
                  cal:Message.Attach="[Click] = [CloseTab()]" />
        <MenuItem Header="Close other tabs" 
                  cal:Message.Attach="[Click] = [CloseOtherTabs()]"
                  IsEnabled="False"
                  Foreground="{Binding Source={StaticResource proxy}, Data.MenuItemForeground}"/>
        <MenuItem Header="Close all tabs" 
                  cal:Message.Attach="[Click] = [CloseAllTabs()]"
                  IsEnabled="False"
                  Foreground="{Binding Source={StaticResource proxy}, Data.MenuItemForeground}"/>
     </ContextMenu>
</TextBlock.ContextMenu>

Don't forget to declare the helper namespace import at the top of your Window/UserControl.

Lee O.
  • 3,212
  • 2
  • 26
  • 36
  • Hi Lee, Thank you for trying to help me. Help is greatly appreciated. I tried your method and got produced with this error `A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll Additional information: Cannot call MarkupExtension.ProvideValue because of a cyclical dependency. Properties inside a MarkupExtension cannot reference objects that reference the result of the MarkupExtension. The affected MarkupExtensions are: System.Windows.Data.Binding System.Windows.Data.Binding` – Master Feb 04 '15 at 21:28
  • Ok...I was unaware of this limitation (http://stackoverflow.com/questions/12871551/binding-the-width-property-of-a-datagridcolumn-to-the-actualwidth-of-the-parent). I'll update with another option. – Lee O. Feb 04 '15 at 21:49
  • Hi Lee, sorry for late response. I tried your method but still nothing =( Same results. – Master Feb 12 '15 at 18:47