如何使用宽度可调整的固定列自定义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
派生,这是不够的绑定。基本上,为了让这些人工作,目标对象需要是从FrameworkElement
或FrameworkContentElement
派生的类型,它应该是视觉或逻辑树的一部分(而不是其中的DataGridColumn
)。请注意,该需求的例外情况很少(例如在资源字典中定义的Freezable
),而且即将推出新版本的框架。
因此,不幸的是,您需要明确指定Binding.Source
(它应该是您的CustomDataGrid
类的一个实例)。我想不出在XAML(Source={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
到视图模型属性不会像往常一样工作)。
您需要以编程方式在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()是做正确的时间,有可能是一个更好的方法来覆盖,但这是概念,我会去到做这个工作。
这非常符合我的需求!无论如何,我只添加了“DataContext = this”来澄清示例:) – Martijn