Search code examples
wpfdatagriddatagridtemplatecolumn

Invoke command on a DataGridcolumn with single-click


I would like to create a hyperlink-column in wpf but rather with a command-binding instead of an uri.

 <DataGridTemplateColumn Header="{lex:Loc newmaterialnumber}" Width="*">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock TextDecorations="Underline" Text="{Binding NewMaterialnumber}"  Cursor="Hand" VerticalAlignment="Center" HorizontalAlignment="Left">
                            <TextBlock.InputBindings>
                                <MouseBinding MouseAction="LeftClick" Command="{Binding DataContext.OpenNewMaterialnumberCommand, RelativeSource={RelativeSource AncestorType={x:Type local:ArticleInfoSearchWindow}}}" />
                            </TextBlock.InputBindings>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

This works great but I have to select the row first before I can click the link. It would be achievable with a datatrigger which sets the row to selected on hover, but I don't really want do select the row on hover.

Any better ideas?


Solution

  • I came up with this solution. First of all create a new DataGridCommandColumn inherited by DataGridBoundColumn.

    public class DataGridCommandColumn : DataGridBoundColumn
    {
        [Bindable(true)]
        public ICommand Command
        {
            get => (ICommand)GetValue(CommandProperty);
            set => SetValue(CommandProperty, value);
        }
    
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
            nameof(Command),
            typeof(ICommand),
            typeof(DataGridCommandColumn));
    
        [Bindable(true)]
        public int FontSize
        {
            get => (int)GetValue(FontSizeProperty);
            set => SetValue(FontSizeProperty, value);
        }
    
        public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
            nameof(FontSize),
            typeof(int),
            typeof(DataGridCommandColumn));
    
    
        protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
        {
            throw new NotImplementedException();
        }
    
        protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
        {
            var button = new Button();
    
            button.SetResourceReference(FrameworkElement.StyleProperty, "ToolButonWithDisabledRecognizesAccessKey");
            button.SetResourceReference(Control.ForegroundProperty, "PrimaryHueMidBrush");
    
            button.Height = 20;
            button.VerticalContentAlignment = VerticalAlignment.Top;
            button.HorizontalContentAlignment = HorizontalAlignment.Left;
            button.HorizontalAlignment = HorizontalAlignment.Left;
            button.Padding = new Thickness(0);
            button.FontWeight = FontWeights.Normal;
            if (FontSize != 0)
            {
                button.FontSize = FontSize;
            }
    
    
            button.Click += Button_Click;
            BindingOperations.SetBinding(button, ContentControl.ContentProperty, Binding);
    
            return button;
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (Command == null)
            {
                return;
            }
    
            if (Command.CanExecute(null))
            {
                Command.Execute(null);
            }
        }
    }
    

    Then create a proxy:

    public class ViewModelProxy : Freezable
    {
        protected override Freezable CreateInstanceCore()
        {
            return new ViewModelProxy();
        }
    
        public ViewModelBase ViewModel
        {
            get => (ViewModelBase)GetValue(ViewModelProperty);
            set => SetValue(ViewModelProperty, value);
        }
    
        public static readonly DependencyProperty ViewModelProperty = 
            DependencyProperty.Register("ViewModel", typeof(ViewModelBase), typeof(ViewModelProxy), new UIPropertyMetadata(null));
    }
    

    Later you can use it:

    <utility:ViewModelProxy  x:Key="ViewModelProxy" ViewModel="{Binding}" />
    
    <controls:DataGridCommandColumn Header="{lex:Loc submissionnumber}" Binding="{Binding SubmissionNumber}"  Command="{Binding ViewModel.OpenReceivableSubmissionNumberCommand,  Source={StaticResource ViewModelProxy}}" Width="Auto"  />