Datagridcolumn: Binding Visibility and Width via BindingProxy show different behavior
Asked Answered
P

1

0

As the columns of a data grid aren't in the visual tree of datagrid I'm m using this approach of Binding Proxy to bind Visibility of a DataGridTextColumn.

https://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

For some reason I would like to understand the same approach does work fine for Visibility but not for column's Widthproperty. Could someone explain this different behavior to me?

Code sample

c#

class BindingProxy : Freezable
{
    #region Override of Freezable
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
    #endregion //Override of Freezable

    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 Column(bool visible = true)
    {
        if (visible == true)
            Visible = Visibility.Visible;
        else
            Visible = Visibility.Collapsed;

        Width = 200;
    }

    public Visibility Visible
    {
        get { return m_visible; }
        set { m_visible = value; OnPropertyChanged("Visible"); }
    }
    Visibility m_visible;

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

    double m_width;
}

just to make it easier to reproduce

public partial class MainWindow : Window
{
    public MainWindow()
    {


        Lines = new ObservableCollection<tableline>();


        for (int i = 0; i< 5; i++)
            Lines.Add(new tableline());

        Columns = new List<Column>();
        Columns.Add(new Column(true));
        Columns.Add(new Column(false));

        InitializeComponent();
        DataContext = this;
    }

    public List<Column> Columns { get; set; }
    public ObservableCollection<tableline>Lines { get; set; }
}

public class tableline
{
    public tableline()
    {
        Result = new List<string>();
        int colCount = 2;
        for (int i = 0; i < colCount; i++)
        {
            Result.Add(i.ToString() + " some text");
        }

    }
    public List<string> Result { get; set; }
}

xaml

<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]}" Visibility="{Binding Data.Columns[0].Visible, Source={StaticResource proxy}}" Width="{Binding Data.Columns[0].Width, Source={StaticResource proxy}}" />
        <DataGridTextColumn Header="ProductId2" Binding="{Binding Path=Result[1]}" Visibility="{Binding Data.Columns[1].Visible, Source={StaticResource proxy}}" Width="{Binding Data.Columns[1].Width, Source={StaticResource proxy}}"/>
    </DataGrid.Columns>
</DataGrid>

Just for you to know what my original goal is. I would like to set a width to auto for all columns, but with a "maximum" column width during drawing of datagrid. However, user should be possible to resize over this limit. That's why i can't use MaxColumnWidth So I thought easiest way to realize this would be to read width for every column and set it to "maximum" value if it's bigger than limit.

Phosphor answered 17/10, 2017 at 9:53 Comment(0)
L
1

The type of the Width property of a DataGridColumn is DataGridLength and not double.

Change type of your source property:

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

DataGridLength m_width;

And the Mode of the Binding:

<DataGridTextColumn Header="ProductId1" Binding="{Binding Path=Result[1]}"
                    Visibility="{Binding Data.Columns[0].Visible, Source={StaticResource proxy}}" 
                    Width="{Binding Data.Columns[0].Width, Source={StaticResource proxy}, Mode=TwoWay}" />
Lallation answered 17/10, 2017 at 10:2 Comment(1)
Works perfectly. Thanks a lot. Could you add this to your response here, too? Seems to be the same problem https://mcmap.net/q/912930/-wpf-xaml-trying-to-bind-the-width-of-a-datagrid-column. I may not add a comment there yet :-)Phosphor

© 2022 - 2024 — McMap. All rights reserved.