8

Is there any way I can associate a Command with a DataGridHyperlinkColumn? I've tried this:

   <DataGridHyperlinkColumn Header="Client Name" Binding="{Binding ShortName}">
     <DataGridHyperlinkColumn.ElementStyle>
      <Style TargetType="TextBlock">
       <Setter Property="Hyperlink.Command" 
                                    Value="{Binding DataContext.NavigateToClientCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ClientsSummaryView}}}"/>
                            <Setter Property="Hyperlink.CommandParameter" Value="{Binding}"/>
                        </Style>
                    </DataGridHyperlinkColumn.ElementStyle>
    </DataGridHyperlinkColumn>

At runtime, I can see that the binding is being correctly evaluated (the property getter for the Command is called), but the Command is not executed when I click the hyperlink. Is there a better way to do this?

Thanks,

Daniel

dks1983
  • 165
  • 2
  • 8

2 Answers2

13

Are you sure the command is being associated with the hyperlink? I tried setting this up in a sample app, and the command wasn't being associated with the hyperlink (if you return false from CanExecute, you'll be able to quickly determine if it is wired up).

Instead, I created a DataGridTemplateColumn to accomplish this:

<DataGridTemplateColumn Header="Client Name">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock>
                <Hyperlink Command="{Binding DataContext.NavigateToClientCommand, RelativeSource={RelativeSource AncestorType={x:Type local:ClientsSummaryView}}}"
                           CommandParameter="{Binding ShortName}">
                     <TextBlock Text="{Binding ShortName}" />
                </Hyperlink>
            </TextBlock>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

This would get really annoying if you had to create multiple columns. After cracking open the Toolkit with Reflector, it looks like it is supporting the TargetName / NavigationUrl paradigm for using the hyperlink.

If you have a scenario where you would require this type of column in many places, I would suggest extending the DataGridHyperlinkColumn and adding a Command property. You could then modify the element returned from GenerateElement so that it used your command.

Abe Heidebrecht
  • 30,090
  • 7
  • 62
  • 66
  • Abe: thanks. I was hoping to shortcut around DataGridTemplateColumn, but, honestly, it doesn't look much worse than what I had. Thanks again! – dks1983 Apr 19 '10 at 13:24
  • Can you explain how the `` works? It looks very complicated. – Dai Feb 24 '17 at 06:33
  • @Dai - this is a `RelativeSource` binding to an `ICommand` property on the `DataContext` of the `ClientsSummaryView` where this column is added. This question asked about these types of bindings, and hopefully will help you understand it better: http://stackoverflow.com/questions/84278/how-do-i-use-wpf-bindings-with-relativesource/84317#84317 – Abe Heidebrecht Feb 27 '17 at 15:46
1

Yes, but not with the standard DataGridHyperlinkColumn. You need to enhance that class a little.

public class DataGridHyperlinkColumn : System.Windows.Controls.DataGridHyperlinkColumn
{
    /// <summary>
    /// Support binding the hyperlink to an ICommand rather than a Uri
    /// </summary>
    public BindingBase CommandBinding { get; set; }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var result = base.GenerateElement(cell, dataItem);

        if (((TextBlock)result).Inlines.FirstInline is Hyperlink link)
            BindingOperations.SetBinding(link, Hyperlink.CommandProperty, CommandBinding);

        return result;
    }
}

After setting up the correct namespace mapping you can then do this:

<c:DataGridHyperlinkColumn Header="Booking" Binding="{Binding Path=ReservationNo}" CommandBinding="{Binding Path=NavigateCommand}" />

This assumes that NavigateCommand exists on your viewmodel object.

Phil Degenhardt
  • 7,215
  • 3
  • 35
  • 46