Question

My DataGrid is bound to a data source, which is a database. When user right clicks somewhere over the DataGrid control, I'd like to be able to recognize over which column he or she did it. Scenario is as follows - if ContextMenu is opened over a column holding dates, then (for example) I would like to present him with options to filter out dates smaller, greater or equal to the date selected.

<DataGrid.Resources>
        <Helpers:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

<DataGrid.ContextMenu>
        <ContextMenu DataContext="{Binding Path=DataContext}">
            <MenuItem Header="Cokolwiek" Command="{Binding Source={StaticResource proxy}, Path=Data.FK}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent.PlacementTarget.DataContext}"/>
        </ContextMenu>
</DataGrid.ContextMenu>

PlacementTarget is a reference to the DataGrid, and I'd like it to be a reference to DataGridColumn.

BindingProxy class:

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

    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));
}
Was it helpful?

Solution

What you can do is hook up to the PreviewMouseUp event so you can look at the Source property of the Event that is raised.

With the exception of direct events, WPF defines most routed events in pairs - one tunnelling and the other bubbling. The tunnelling event name always begins with 'Preview' and is raised first. This gives parents the chance to see the event before it reaches the child. This is followed by the bubbling counterpart. In most cases, you will handle only the bubbling one. The Preview would be usually used to

block the event (e.Handled = true) cause the parent to do something in advance to normal event handling.

e.g. if UI Tree = Button contains Grid contains Canvas contains Ellipse Clicking on the ellipse would result in (MouseDownButton is eaten up by Button and Click is raised instead.)

private void OnPreviewMouseUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
    {
        var source = mouseButtonEventArgs.Source;
        // Assuming the DataGridColumn's Template is just a TextBlock
        // but depending on the Template which for sure should at least inherit from FrameworkElement to have the Parent property.
        var textBlock = source as TextBlock;
        // Not a good check to know if it is a holding dates but it should give you the idea on what to do
        if (textBlock != null)
        {
            var dataGridColumn = textBlock.Parent as DataGridColumn;
            if (dataGridColumn != null)
            {
                if ((string) dataGridColumn.Header == "Holding Dates")
                {
                    // Show context menu for holding dates
                }

            }
        }
            // Other stuff
        else if (somethingElse)
        {
            // Show context menu for other stuff
        }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top