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
}