0

I know that there are similar questions on SO.

I have reviewed them, tried them, tried combinations of them, and retried them for the past day an half with very little success. I'm apparently dense or missing something.

The basic approaches covered were:

  • Placement Target
  • Using the Tag Attribute on a Parent
  • Using Ancestor Relative Source
  • Making use of ElementName root for the DataContext

Nothing seems to work and in only one instance am I even able to hit a break point in a Test Converter to see whats being bound. It will only work in the Tag Attribute of the DataCell. I am exasperated. This is as close as I have gotten:

<xcdg:DataGridControl.Resources>
    <Style TargetType="{x:Type xcdg:DataCell}">
        <Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding RelativeSource={RelativeSource AncestorType={ x:Type xcdg:DataCell}}, Path=Tag, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>                        
            </Style>
 </xcdg:DataGridControl.Resources>

As a variation on this approach I thought that sense the Binding on the Tag Attribute worked and was correct that I could use in the DataContext for the ContextMenu or the even just the MenuItem itself.

<ContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" StaysOpen="True"> 

or

<MenuItem  Header="Acknowledge" DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" Command="{Binding Path=AcknowledgeViolationCommand}"  />

With this next one I also tried PlacementTarget.DataContext and PlacementTarget.Tag with no results.

        <Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding PlacementTarget, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>     

Other attempts:

        <Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding PlacementTarget, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem DataContext="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=DataContext}"  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>                        

Here I tried making use of the ElementName root approach in different ways but it would only work in the Tag for the Cell and not the DataContext or Tag for the ContextMenu

        <Setter Property="Tag" Value="{Binding DataContext, ElementName=root}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding PlacementTarget, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=PacementTarget.Tag.AcknowledgeViolationCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource TestConverter}}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>         

<!-- variation of above --> 
        <Setter Property="Tag" Value="{Binding DataContext, ElementName=root}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Mode=Self}, Path=PlacementTarget.DataContext, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>                        

<Setter Property="ContextMenu">
                        <Setter.Value>
                            <ContextMenu DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource TestConverter}}" StaysOpen="True">
                                <MenuItem Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                            </ContextMenu>
                        </Setter.Value>
                    </Setter>

I can list countless failed attempts. PlacementTargets, Tags, Ancestors, RelativeSources, why can't I make this work?. And why can I only seem to step into my TestConverter when its used on the DataCell Tag Binding and no where else?

Heres the Convert Method:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }

When it fires for Tag binding I can actually see the ViewModel being passed just like I want and I can even execute my Command from the immediate window. Frankly I'm at my wits end on what should have been a 15 minute thing.

Can anyone tell me what I'm doing or wrong?

Additional Example(s) From Lee O.s Comment I tried the BindingProxy approach without any luck.

<xcdg:DataGridControl.Resources>
                <vl:BindingProxy x:Key="proxy" Data="{Binding }" />
                <Style TargetType="{x:Type xcdg:DataCell}">
<Setter Property="ContextMenu">
                        <Setter.Value>
                            <ContextMenu DataContext="{StaticResource proxy}" StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                            </ContextMenu>
                        </Setter.Value>
                    </Setter>
                </Style>

Additional tries. These next attempts did do something new. Now at least when the app is started the breakpoint for the AcknowledgeViolationCommand fires once. However selecting the Item from the Context Menu still does nothing.

<ContextMenu DataContext="{Binding Data, Source={StaticResource proxy}}" StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                            </ContextMenu>

and

<ContextMenu StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=Data.AcknowledgeViolationCommand, Source={StaticResource proxy}}"  />
                            </ContextMenu>

also tried x:Reference with the following:

<Setter Property="ContextMenu">
                        <Setter.Value>
                            <ContextMenu StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=DataContext.AcknowledgeViolationCommand, Source={x:Reference dummyControl}, Converter={StaticResource TestConverter}}"  />
                            </ContextMenu>
                        </Setter.Value>
                    </Setter>

These approaches all have one thing in common in that they all seem to cause a breakpoint I have set in the command to hit ONCE as the grid loads. Further more adding the TestConverter to the reference and setting a breakpoint causes it to hit once for each row in the grid as it loads, but never when the command is clicked.

Here is the code for the Command in the ViewModel

public ICommand AcknowledgeViolationCommand
    {
        get
        {
            if (acknowledgeViolationCommand == null)  // BreakPoint is here
                acknowledgeViolationCommand = new RelayCommand(param => Test());


            return acknowledgeViolationCommand;
        }
    }

private void Test()
    {
        string a = "a"; //Breakpoint here
    }

Made a change to the command in case for some reason it was wanting the canExecute predicate. I confirmed the breakpoint for the canExecute method does fire.

public ICommand AcknowledgeViolationCommand
    {
        get
        {
            if (acknowledgeViolationCommand == null) // BP here
                acknowledgeViolationCommand = new RelayCommand(param => Test(), param => YesDoIt());

            return acknowledgeViolationCommand;
        }
    }

private bool YesDoIt()
    {
        return true;  //BP here
    }
jrandomuser
  • 1,510
  • 19
  • 50
  • 1
    RelativeSource bindings will not work on elements that are not a part of the Visual Tree. A ContextMenu is an example of one such element. One option is my answer at http://stackoverflow.com/questions/25040512/bind-to-a-dependency-property-that-is-in-parents-datacontext/25042297#25042297 (the BindingProxy solution). – Lee O. Oct 02 '14 at 18:48
  • 1
    @jrandomuser - Check out the answer [here](http://stackoverflow.com/a/21356695/632337). – Rohit Vats Oct 02 '14 at 19:06
  • @LeeO. I tried it and had no luck. I will update the examples with what I did. – jrandomuser Oct 02 '14 at 19:14
  • your DataContext binding is wrong. It should be DataContext="{Binding Data, Source={StaticResource proxy}}" – Lee O. Oct 02 '14 at 19:19
  • @LeeO. Updated again. I got closer in that it initially hits the Command as the its loading, but selecting the item in the context menu still doesn't cause anything. I'm not sure I understand what causes the AcknowledgeViolationCommand to fire when the grid is loading though? – jrandomuser Oct 02 '14 at 19:27
  • @RohitVats Tried the Freezable part of your posted solution with same results as I posted for Lee O.s. Its definitely closer in that the command at least fires initially at start up, but clicking the menuitem still doesn't do anything – jrandomuser Oct 02 '14 at 19:29
  • The command fires or the getter for the property holding the command gets called? My guess is it's the second one. Did you put a breakpoint inside the actual command to test when you click the button or are you expecting the getter of the property to get called? – Lee O. Oct 02 '14 at 19:35
  • @RohitVats I also tried the x:Reference approach but it nets the same effect. The command is called when the Grid loads but not when the menu item is selected. – jrandomuser Oct 02 '14 at 19:36
  • @LeeO. Sorry, the breakpoint is set in the first line of the get for the command "if (acknowledgeViolationCommand == null)". I'll put it in the Question as well. If I put the testconverter in this reference it will fire over and over for each row in the grid as it loads. – jrandomuser Oct 02 '14 at 19:39
  • 1
    @jrandomuser That's not how a command works. When the context menu loads it calls the getter of the AcknowledgeViolationCommand to bind the command to the value of that property. It never will call the getter again (or the converter) unless you change the value of AcknowledgeViolationCommand (and a RaisePropertyChanged call). Clicking the MenuItem will cause the ICommand.Execute method to fire which will call your method Test(). Put the breakpoint in there to validate the command is firing when you click the menu item. – Lee O. Oct 02 '14 at 19:56
  • @LeeO. Sorry I have a breakpoint in it as well. Never fires. However from your description it looks like at least I have addressed one half of the problem, in that the Command itself is now being hit at first like it should. Updated the Question with the Test method and where the BreakPoint is. – jrandomuser Oct 02 '14 at 20:01
  • @LeeO. I also updated the Question with a Predicate Method and reference in the command. I was able to confirm that the BreakPoint is hit at least for the canExecute Predicate method, just never the method itself. – jrandomuser Oct 02 '14 at 20:08
  • /sigh and now for absolutely no reason, and with no changes the Test Method Break Point started hitting.... So it basically all works now. Which don't get me wrong I'm glad that it works, but now for all I know it was fixed through the power of happy thoughts and pixie dust!?! – jrandomuser Oct 02 '14 at 20:20
  • @jrandomuser can you send me some of that pixie dust? – Lee O. Oct 02 '14 at 20:24

0 Answers0