2

since WPF creates column headers automatically based on which class is holding data, I'd like to ask if there is a possibility to override this process?

For example, having this class

public class Report
{
    public string Value { get; set; }
    public int Title { get; set; }
}

I will receive 2 columns - | Value | Title |

As I see it now, WPF creates those columns headers by getting the name of property and "pastes" plain output of what it gets

something like this?

nameof(property);

The goal I want to achieve is to create a custom attribute for the property like

[Header("Price in €")]
public string Value { get; set}

and let WPF create column header based on that attribute, so my columns would be like this -

| Price in € | Title |

My question is how to override this?

Steve
  • 61
  • 8
  • You could set in your xaml autogeneratecolumns to false, and create manually the columns, setting the headers yourself. [check this out](https://www.wpf-tutorial.com/datagrid-control/custom-columns/) – Magnetron Oct 16 '18 at 15:47
  • Yes I know, but I guess I would have to do it programmatically what I want to avoid because with every change in class, let's suppose I would add/delete property, I would have to add/delete column header manually. And also it's more convenient and easier to set column headers in attributes – Steve Oct 16 '18 at 15:50
  • There is an event that is fired when the column is generated, I think it's possible to use it to do what you want, I just don't remember which event it is. I'll check. – Magnetron Oct 16 '18 at 15:51

1 Answers1

2

You can create a simple Behavior for that.

I will use the ComponentModel.DescriptionAttribute in this example, but you can of course use any custom attribute.

using System.ComponentModel;
using System.Windows.Interactivity;

class ExtendendHeadersBehavior : Behavior<DataGrid>
{
    protected override void OnAttached()
    {
        AssociatedObject.AutoGeneratingColumn += AssociatedObject_AutoGeneratingColumn;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.AutoGeneratingColumn -= AssociatedObject_AutoGeneratingColumn;
    }

    private void AssociatedObject_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.PropertyDescriptor is PropertyDescriptor desc)
        {
            string header = desc.Attributes.OfType<DescriptionAttribute>()
                .FirstOrDefault()?.Description;

            if (!string.IsNullOrEmpty(header))
            {
                e.Column.Header = header;
            }
        }      
    }
}

Usage:

<DataGrid>
    <i:Interaction.Behaviors>
        <b:ExtendendHeadersBehavior/>
    </i:Interaction.Behaviors>
</DataGrid>

The namespaces are:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:b="clr-namespace:YourAppNamespace"
dymanoid
  • 14,771
  • 4
  • 36
  • 64
  • How did you add `System.Windows.Interactivity`? I couldn't find the assembly it belongs to. – Magnetron Oct 16 '18 at 16:23
  • @Magnetron, refer to [this question](https://stackoverflow.com/questions/8360209/how-to-add-system-windows-interactivity-to-project). – dymanoid Oct 16 '18 at 16:24
  • It's hard finding, but what I've done is just simply wait till all References load up and then type starting with System then Windows AND THEN Interactivity, Visual Studio is tricky – Steve Oct 16 '18 at 16:48