如何使用宽度可调整的固定列自定义Datagrid控件?

问题描述:

我想要做的是使CustomDatagrid已经有2个固定列。然后我可以重新使用这个CustomDatagrid并添加额外的列以适合我最好的目的。但是当我添加额外的列时,我希望能够调整2个固定列的大小。我试图用依赖属性作为下面的例子来解决它,但无济于事。而且我没有得到任何绑定错误,这让我不知道什么是错的。如何使用宽度可调整的固定列自定义Datagrid控件?

=>这个小例子会澄清什么,我试图做

CustomDataGrid.Xaml

<DataGrid x:Class="DataGridWidthTestControl.CustomDataGrid" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:local="clr-namespace:DataGridWidthTestControl" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 
<DataGrid.Columns> 
    <DataGridTextColumn Width="{Binding Column1Width}" Header="Column1"/> 
    <DataGridTextColumn Width="{Binding Column2Width}" Header="Column2"/> 
</DataGrid.Columns> 

CustomDataGrid.Xaml.CS - 代码隐藏

namespace DataGridWidthTestControl 
{ 
    /// <summary> 
    /// Interaction logic for CustomDataGrid.xaml 
    /// </summary> 
    public partial class CustomDataGrid : DataGrid 
    { 
     public CustomDataGrid() 
     { 
      InitializeComponent(); 
      DataContext = this; 
     } 

     public static readonly DependencyProperty Column1WidthProperty = DependencyProperty.Register("Column1Width", typeof(DataGridLength), typeof(CustomDataGrid), new FrameworkPropertyMetadata(new DataGridLength(25, DataGridLengthUnitType.Star))); 

     public DataGridLength Column1Width 
     { 
      get { return (DataGridLength)GetValue(Column1WidthProperty); } 
      set { SetValue(Column1WidthProperty, value); } 
     } 

     public static readonly DependencyProperty Column2WidthProperty = DependencyProperty.Register("Column2Width", typeof(DataGridLength), typeof(CustomDataGrid), new FrameworkPropertyMetadata(new DataGridLength(15, DataGridLengthUnitType.Star))); 

     public DataGridLength Column2Width 
     { 
      get { return (DataGridLength)GetValue(Column2WidthProperty); } 
      set { SetValue(Column2WidthProperty, value); } 
     } 

    } 
} 

主窗口.xaml(除了默认初始化调用,代码隐藏为空)

<Window x:Class="DataGridWidthTestControl.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:DataGridWidthTestControl" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <local:CustomDataGrid Column1Width="1*" Column2Width="1*" > 
      <DataGrid.Columns> 
       <DataGridTextColumn Width="10*" Header="column3"/> 
      </DataGrid.Columns> 
     </local:CustomDataGrid> 
    </Grid> 
</Window> 

首先你需要知道的是没有绑定(在你的情况等)指定的任何来源,使用Binding.RelativeSource绑定和使用Binding.ElementName不会DataGridColumn工作,因为它直接从DependencyObject派生,这是不够的绑定。基本上,为了让这些人工作,目标对象需要是从FrameworkElementFrameworkContentElement派生的类型,它应该是视觉或逻辑树的一部分(而不是其中的DataGridColumn)。请注意,该需求的例外情况很少(例如在资源字典中定义的Freezable),而且即将推出新版本的框架。

因此,不幸的是,您需要明确指定Binding.Source(它应该是您的CustomDataGrid类的一个实例)。我想不出在XAMLSource={x:Reference (...)}不适用,因为你不能在它的定义中引用一个对象),所以我认为你需要回退到代码隐藏(这是不寻常的当设计自定义控件时)。

最简单的方法就是命名列:

<DataGrid.Columns> 
    <DataGridTextColumn x:Name="Column1" x:FieldModifier="private" Header="Column1" /> 
    <DataGridTextColumn x:Name="Column2" x:FieldModifier="private" Header="Column2" /> 
</DataGrid.Columns> 

x:FieldModifier="private"是可选的),然后在你的控制初始化设置绑定:

public CustomDataGrid() 
{ 
    InitializeComponent(); 
    BindingOperations.SetBinding(Column1, DataGridColumn.WidthProperty, new Binding 
    { 
     Path = new PropertyPath(Column1WidthProperty), 
     Source = this, 
    }); 
    BindingOperations.SetBinding(Column2, DataGridColumn.WidthProperty, new Binding 
    { 
     Path = new PropertyPath(Column2WidthProperty), 
     Source = this, 
    }); 
} 

您可能还需要添加Mode = BindingMode.TwoWay添加到绑定,以便在用户手动调整列的大小时,控件上的值保持同步。

注意,我故意删除的DataContext = this线,因为一)没有必要和B)使用您的控制时,它会给你带来很多的麻烦(例如结合DataGrid.ItemsSource到视图模型属性不会像往常一样工作)。

+0

这非常符合我的需求!无论如何,我只添加了“DataContext = this”来澄清示例:) – Martijn

您需要以编程方式在CustomDataGrid类中插入固定列,而不是在模板中指定它们。

喜欢的东西:

public override void OnApplyTemplate() 
{ 
    if (!this.Columns.Any(c => c.Header.ToString() == "Column1")) 
    { 
     this.Columns.Insert(0, 
          new DataGridTextColumn 
          { 
           Width = this.Column1Width, 
           Header = "Column1" 
          }); 
    } 

    if (!this.Columns.Any(c => c.Header.ToString() == "Column2")) 
    { 
     this.Columns.Insert(1, 
          new DataGridTextColumn 
          { 
           Width = this.Column2Width, 
           Header = "Column2" 
          }); 
    } 

    base.OnApplyTemplate(); 
} 

我不知道OnApplyTemplate()是做正确的时间,有可能是一个更好的方法来覆盖,但这是概念,我会去到做这个工作。