6

I have a TreeListControl that binds to a collection in my VM. I also want to define the context menu inside the treelistcontrol having its header text bind to another string in my VM. how can I set the data context in this case? I tried to

<Window.DataContext>
    <model:ViewModel></model:ViewModel>
</Window.DataContext>
<Grid>
<Button Grid.Row="1"  Command="{Binding CellCheckedCommand}"></Button>

    <TextBlock Text="{Binding HeaderText}" Grid.Row="2">
        <TextBlock.ContextMenu>
            <ContextMenu>
                <MenuItem DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext}"  Header="{Binding HeaderText}"></MenuItem>
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
</Grid>

but it doesn't work.

Here is the ViewModel

public DelegateCommand CellCheckedCommand { get; set; }

private String _HeaderText;

public String HeaderText 
{
    get
    {
        return _HeaderText;
    }
    set
    {
        _HeaderText = value;
        NotifyPropertyChanged("HeaderText");
    }
}

public void NotifyPropertyChanged(String name)
{ 
    if(PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

private void CellCheckedMethod()
{
    HeaderText = "Changed";
}
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Helic
  • 907
  • 1
  • 10
  • 25
  • You are fighting two things, the nature of the context menu (cm) and its parent it resides on. Alone the CM can bound outside its internal visual tree. But once the CM is place on an object that doesn't have a visual tree (as with certain items on a treelist or a datagrid), one is now fighting trying to find the page's visual tree. You have learned about binding, but each control has its own peculiarities. Maybe extend the class of the data of the tree item to point to the current VM(?). That way the binding can access the current VM without having to jump through hoops. – ΩmegaMan Oct 16 '14 at 14:20
  • The most succinct text on binding can be found on MSDN: [Data Binding Overview](http://msdn.microsoft.com/en-us/library/ms752347(v=vs.100).aspx) – ΩmegaMan Oct 16 '14 at 14:23

2 Answers2

5

This binds to a Window:

DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}"

If the command AddItemCommand and property AddItemText are defined on the Window ViewModel, bind to Window DataContext:

DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext}"
lisp
  • 4,138
  • 2
  • 26
  • 43
  • it doesn't work, please see my example below – Helic Oct 14 '14 at 12:35
  • @Helic what would help are short versions of your ViewModels - which has property HeaderText, AddItemText, AddItemCommand, because it's impossible to tell from .xamls alone, what your'e trying to achieve. – lisp Oct 14 '14 at 12:53
  • +1 For Relative example. I added it to my second update. – ΩmegaMan Oct 15 '14 at 21:33
  • 2
    This doesn't work because ContextMenu is not in the visual tree so it will never find x:Type Window – user99999991 May 26 '15 at 17:36
4

Provide a name for your window and explicitly bind to it such as

<window  x:Name="ReportsPage"/>

...

 <MenuItem DataContext="{Binding ElementName=ReportsPage}"/>

UPDATE

Since the context menu is actually in its own window, binding is a bit trickier. Hence the best bet is to walk up the RelativeSource to the context's parent and pull the header text from there:

    <Window.DataContext>
        <local:MainVM HeaderText="Jabberwocky" />
    </Window.DataContext>

    ...

<TextBlock Text="{Binding HeaderText}">
    <TextBlock.ContextMenu>
        <ContextMenu>

<MenuItem Header="{Binding Path=Parent.DataContext.HeaderText, 
                    RelativeSource={RelativeSource Self}}" />

        </ContextMenu>
    </TextBlock.ContextMenu>

Which for this context produces this

enter image description here

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
  • @Helic add `Path=DataContext`. – ΩmegaMan Oct 15 '14 at 15:45
  • @Helic Understood. I will attempt an example and delete my post until I can get it working. – ΩmegaMan Oct 15 '14 at 16:27
  • @Helic I failed to fully qualify the binding with `DataContext`. See my update. – ΩmegaMan Oct 15 '14 at 21:18
  • Many thanks for different solutions. what do you mean by design time for the last solution? Also, I tried them with ContextItem's Header, none of them works, but they DO work for TextBlock – Helic Oct 16 '14 at 08:19
  • ContextMenu doesn't support datacontext, used the solution in this post http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/, works fine for me now. – Helic Oct 16 '14 at 09:48
  • @Helic My bad, I stepped away from your perfect example for speed. You don't need a *proxy* in this situation. See the update example I provide on the `RelativeSource` binding to itself and step into the parent's data context which holds the page context. – ΩmegaMan Oct 16 '14 at 10:40
  • why the previous solutions don't work with MenuItem? – Helic Oct 16 '14 at 11:13
  • @Helic The context menu is really a popup window outside the main window. The xaml processing is localized enough that binding to the main window is not possible as it works around the popup's visual tree. – ΩmegaMan Oct 16 '14 at 11:18
  • you mean for any popup window, we cannot use the normal apporoach for data binding, instead, we need to bind to an item in the visual tree in the main window and borrow its data context? My understanding may be wrong. – Helic Oct 16 '14 at 12:30
  • @Helic The visible tree is different for the context menu and datagrid columns. Each has different issues. Normally most items reside in the visible tree and binding flows accordingly. You found one of the two edge cases for binding on a page. :-) – ΩmegaMan Oct 16 '14 at 12:31
  • my real work case is to create a contextmenu for TreeListControl, the proxy solution works, but not the Parent one. Do you know if there is any good documentation on wpf controls? – Helic Oct 16 '14 at 12:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/63172/discussion-between-omegaman-and-helic). – ΩmegaMan Oct 16 '14 at 14:50