SoFunction
Updated on 2025-03-06

A brief analysis of the problem of datagrid display columns in wpf

This will generate 3 columns

List<Person> list = new List<Person>();

            (new Person { Name = "Zhang San", Age = 22, Address = "Daba Village, Cheban Town, Lianjiang City, Guangdong Province" });
            (new Person { Name = "Li Si", Age = 23, Address = "Jingdezhen City, Jiangxi Province" });
            (new Person { Name = "Wang Wu", Age = 24, Address = "Hongkou District, Shanghai" });

There will also be three columns, how to solve this problem?

             = list;             
            <>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                <DataGridTextColumn Header="age" Binding="{Binding Age}" />
                <DataGridTextColumn Header="address" Binding="{Binding Address}" />
            </>

Judging from the code you provide, the DataGrid column seems to be defined twice: once by binding the ItemsSource property to a list containing Person objects, and the other time by statically defining three DataGridTextColumn columns in XAML. Normally, if you do not set AutoGenerateColumns="True", DataGrid should not automatically generate columns. However, if you find that the columns are added repeatedly in the actual running application, this is usually because the AutoGenerateColumns property defaults to True, causing DataGrid to generate both the data source-based columns and the columns defined in XAML.

To resolve this, make sure the AutoGenerateColumns property is explicitly set to False so that DataGrid only uses columns defined in XAML:

<DataGrid x:Name="datagrid" 
          SelectionMode="Extended"
          IsReadOnly="True" 
          HorizontalAlignment="Left"
          AutoGenerateColumns="False"
          SelectionChanged="datagrid_Selected">
    <>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
        <DataGridTextColumn Header="age" Binding="{Binding Age}" />
        <DataGridTextColumn Header="address" Binding="{Binding Address}" />
    </>
</DataGrid>

In this fix, AutoGenerateColumns="False" was added to the DataGrid's property, which will prevent DataGrid from automatically creating columns based on the data source. This way, DataGrid will only display columns defined in the <> node.

If AutoGenerateColumns = "False" is not applicable, how to modify this code better?

If you don't want to use AutoGenerateColumns="False", you should rely entirely on DataGrid's ability to automatically generate columns from data sources without explicitly declaring columns in XAML.

To do this, you should remove the <> node from XAML, because DataGrid will automatically generate columns for you based on the public properties of the data object bound to ItemsSource. This requires that each public property of your data object (in this case the Person class) will become a column of the DataGrid.

Here is an updated XAML example where the static definition of the column is removed:

<DataGrid x:Name="datagrid" 
          SelectionMode="Extended"
          IsReadOnly="True" 
          HorizontalAlignment="Left"
          SelectionChanged="datagrid_Selected">
    <!--  section is removed to rely on auto-generated columns -->
</DataGrid>

In the background code, you keep the settings for ItemsSource:

public MainWindow()
{
    InitializeComponent();

    List&lt;Person&gt; list = new List&lt;Person&gt;
    {
        new Person { Name = "Zhang San", Age = 22, Address = "Daba Village, Cheban Town, Lianjiang City, Guangdong Province" },
        new Person { Name = "Li Si", Age = 23, Address = "Jingdezhen City, Jiangxi Province" },
        new Person { Name = "Wang Wu", Age = 24, Address = "Hongkou District, Shanghai" }
    };

     = list;
}

After doing this, when you run the application, DataGrid will only display the properties from the Person object list as columns, without any columns that are statically defined in XAML. The advantage of this approach is that it simplifies XAML so that any changes to data objects (such as Person classes) are automatically reflected on the columns of DataGrid. The downside is that you will lose the fine-grained control you can do when defining columns directly in XAML, such as setting column widths and formatting. If you need these controls, you can programmatically configure the automatically generated columns in your background code, or simply keep AutoGenerateColumns="False" and explicitly define your columns in XAML.

The column shows English, what if I want to show Chinese, or other languages?

If you want the column headers in DataGrid to appear in Chinese or other languages, rather than the name of the attribute in the data source, you can set the header attribute for each column when binding. If you do not use AutoGenerateColumns="False", you cannot preset the column title in XAML because the column is automatically generated. However, you can change the column title by handling the AutoGeneratingColumn event of DataGrid in the code background.

Here is an example of how to handle the AutoGeneratingColumn event in the background code to set the column title to Chinese:

In XAML, add the AutoGeneratingColumn event handler for DataGrid:

<DataGrid x:Name="datagrid" 
          SelectionMode="Extended"
          IsReadOnly="True" 
          HorizontalAlignment="Left"
          SelectionChanged="datagrid_Selected"
          AutoGeneratingColumn="datagrid_AutoGeneratingColumn">
</DataGrid>

In the background code (C#), add the implementation of the datagrid_AutoGeneratingColumn event handler:

private void datagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    // Check the generated column and set the Chinese title    if ( == "Name")
    {
         = "Name";
    }
    else if ( == "Age")
    {
         = "age";
    }
    else if ( == "Address")
    {
         = "address";
    }
    // For other languages, you can also set the corresponding title here    // For example, if you need Japanese, you can set it to = "prefix"; etc.}

This code checks every automatically generated column and sets its Header property to the Chinese string you provide. This way, even if the columns are automatically generated based on the properties of the data source, you can still control their display titles.

This approach provides the flexibility to customize column titles based on the column's attribute name at runtime, so that multilingual support can be implemented even if you are using the ability to automatically generate columns.

Is there any other way?

If you want the Chinese column names to be displayed in DataGrid and do not use the AutoGenerateColumns="False" attribute, you can also solve it by binding to a data source with the Chinese attribute name. This involves using a data converter or creating a new data type that contains a Chinese attribute name. However, this is usually not the recommended approach, as it may involve refactoring your data model to suit the needs of UI display, which is not a best practice for data models.

In addition to setting column headers directly in the AutoGeneratingColumn event, there are some other strategies to consider:

Internationalization with resource files

If your application needs to support multiple languages, you can use resource files to achieve internationalization:

Create a resource file for each language (for example, for Simplified Chinese, for English).

Define a resource key-value pair for each column name in the resource file.

Replace the default column name with a string from the resource file in the AutoGeneratingColumn event.

private void datagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
     = ();
}

Use the DisplayName property

If your data model allows, you can use the DisplayName property on the model properties to specify the column name. DataGrid does not use this property directly, but you can use it in the AutoGeneratingColumn event to get the column name.

[DisplayName("Name")]
public string Name { get; set; }

Then, read this property in the AutoGeneratingColumn event:

private void datagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    var displayNameAttribute = [typeof(DisplayNameAttribute)] as DisplayNameAttribute;
    if (displayNameAttribute != null)
    {
         = ;
    }
}

Explicitly declare column binding and column header

This is not an automated approach, but it allows you to fully control the creation of columns in XAML, including column headers and bindings.

In this case, you set AutoGenerateColumns to False and explicitly declare each column, just like in the previous example. If the property name of the data source changes, you also need to update the XAML code.

Summarize

The AutoGeneratingColumn event handler is a standard way to handle automatically generating columns and specifying custom column headers for them. Internationalization with resource files or using DisplayName attributes in your data model provides additional flexibility and multilingual support. In many cases, choosing the best approach depends on the specific needs of your application and the complexity of the data model.

This is the end of this article about a brief analysis of the datagrid display column in wpf. For more related wpf datagrid display column content, please search for my previous article or continue browsing the related articles below. I hope everyone will support me in the future!