【问题标题】:How to bind datagrid columns width in WPF (MVVM)如何在 WPF (MVVM) 中绑定数据网格列的宽度
【发布时间】:2015-05-14 15:24:09
【问题描述】:

我正在尝试绑定数据网格列的宽度,但不起作用。

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

这是后端代码:

public int GridNameWidth
{
    get
    {
        return 300;
    }
}

后端代码永远不会被触及。没有错误,但 name 字段具有默认宽度。我想让宽度绑定到我的属性。我不需要双向绑定,只需要在加载网格时绑定宽度。这在 wpf 中可能吗?

【问题讨论】:

  • 你的数据结构是什么样的?包含您的Name 属性的同一对象是否也包含您的GridNameWidth 属性?
  • 正确,同一个对象包含我的 Name 对象。
  • 通过模型属性设置视觉对象的宽度不是 mvvm。

标签: c# wpf c#-4.0 mvvm


【解决方案1】:

DataGridTextColumn 是一个抽象对象,实际上并不是 VisualTree 的一部分,因此它不会像其他控件那样使用继承的 DataContext。

WPF 知道如何正确解析 Binding 之类的属性并将绑定转移到每个单元格,但是像 Width 之类的东西只是按原样进行评估,并且由于 DataContext 和 VisualTree 都没有按预期存在,因此无法正确评估.

一个常见的解决方案是使用静态数据源来编写绑定。这是一个基于this answer 的示例,它使用x:Reference 从XAML 标记中引用另一个控件:

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

或者,您可以定义自己的DataGridCellTemplate,并使用控件将其宽度绑定到 DataItem 上的任何属性

【讨论】:

  • 这可能是对的,但我还是不明白。你是说我不应该使用我的“GridNameWidth”属性,而是在窗口上使用另一个控件?我阅读了另一个答案,但他没有给出明确的例子。
  • @Luke101 问题是生成 UI 时 DataGridTextColumn 实际上并不存在,因此绑定无法正确评估。作为替代方案,我们可以将绑定设置为在生成单元格时将存在的静态内容。 Source={x:Reference ...} 的意思是“在 XAML 中找到名为 XXX 的对象并将其用作此绑定的源”,因此理论上我们可以将其与 Path=DataContext.NameColumnWidth 结合使用来告诉它使用来自 MyDataGrid.DataContext.NameColumnWidth 的值
【解决方案2】:

正如已经提到的,这里的问题是 DataGridTextColumn 不在逻辑树或可视树中。 另一种解决方案是这种基于提供绑定的绑定代理的方法。 https://stackoverflow.com/a/46787502/5381620

源代码

<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;
}

对于此实现,请直接在 DataContext 中使用 List&lt;Column&gt; 或 ObservableCollection,否则调整绑定。

【讨论】:

  • 您能否添加更多关于如何实施该解决方案的描述?
  • 我希望这会有所帮助,M.K. :-)
【解决方案3】:

如果你想让它工作,你的 GridNameWidth 应该是 DataGridLength 类型。

【讨论】:

  • 为 double 类型定义了一个隐式转换器。见referencesource.microsoft.com/#PresentationFramework/Framework/…
  • 有没有办法让它使用 MVVM 工作?如果不是,我将如何使用您的方式?
  • 你可以使用双精度。或者为 int 实现一个值转换器。
  • 您的 GridNameWidth 属性在哪里?在后面的代码中还是在 ViewModel 中?
  • System.Windows.Data 错误:2:找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement。绑定表达式:路径=网格名称宽度;数据项=空;目标元素是“DataGridTextColumn”(HashCode=738321);目标属性是“宽度”(类型“DataGridLength”)
猜你喜欢
  • 1970-01-01
  • 2017-06-11
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
  • 2010-09-22
  • 2013-12-03
  • 1970-01-01
  • 2012-03-07
相关资源
最近更新 更多