简体   繁体   中英

How to bind datagrid columns width in WPF (MVVM)

I am trying to bind a datagrid columns width but not working.

<DataGridTextColumn Binding="{Binding Name}" Width="{Binding GridNameWidth}" Header="Name" />

Here is the backend code:

public int GridNameWidth
{
    get
    {
        return 300;
    }
}

The backend code is never touched. There are no errors but the name field has a default width. I'd like to make width bind to my property. I don't need two-way binding just need the width to be binded when the grid loads. Is this possible in wpf?

The DataGridTextColumn is an abstract object that isn't actually part of the VisualTree, so it doesn't make use of an inherited DataContext like you would expect with other controls.

WPF knows how to parse something like the Binding property correctly and transfer the binding to each Cell, however something like Width simply gets evaluated as-is, and does not evaluate correctly because neither the DataContext nor VisualTree is there as expected.

A common solution is to write your binding using a static data source instead. Here's an example based on this answer , which uses x:Reference to refer to another control from the XAML markup :

{Binding Source={x:Reference MyDataGrid}, Path=DataContext.NameColumnWidth}

Alternatively, you can define your own DataGridCellTemplate with a control that has it's Width bound to whatever the property is on your DataItem

As already mentioned the issue here is that DataGridTextColumn isn't in the logical or visual tree. An alternative solution is this approach based on a binding proxy providing a binding. https://stackoverflow.com/a/46787502/5381620

SourceCode

<DataGrid ItemsSource="{Binding Lines}" AutoGenerateColumns="False" >
    <DataGrid.Resources>
        <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Header="ProductId1" Binding="{Binding Path=Result[0]}" Width="{Binding Data.Columns[0].Width, Source={StaticResource proxy}, Mode=TwoWay}" />
        <DataGridTextColumn Header="ProductId2" Binding="{Binding Path=Result[1]}" Width="{Binding Data.Columns[1].Width, Source={StaticResource proxy}, Mode=TwoWay}"/>
    </DataGrid.Columns>
</DataGrid>

class BindingProxy : Freezable
{
    //Override of Freezable
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }
    public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}


public class Column : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;
    protected internal void OnPropertyChanged(string propertyname)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
    }

    public DataGridLength Width
    {
        get { return m_width; }
        set { m_width = value; OnPropertyChanged("Width"); }
    }
    DataGridLength m_width;
}

For this implementation use a List<Column> or ObservableCollection directly in DataContext else adjust binding.

如果您希望其工作,那么GridNameWidth的类型应为DataGridLength。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM