如何拥有具有固定列的自定义数据网格控件,其宽度可调

本文关键字:控件 网格 数据网 数据 自定义 拥有 何拥有 | 更新日期: 2023-09-27 18:17:13

我要做的是使一个CustomDatagrid已经有2个固定列。然后我可以重用这个CustomDatagrid并添加额外的列来满足我的最佳目的。但是,当我添加额外的列,我希望能够调整2固定列。我试着用依赖属性作为下面的例子来解决它,但无济于事。我没有得到任何绑定错误,这让我不知道是什么错了。

=>这个小例子将阐明我要做什么

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 - Codebehind

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 (codebehind为空,除了默认的初始化调用)

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

如何拥有具有固定列的自定义数据网格控件,其宽度可调

您需要以编程方式在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()是正确的时间去做它,可能有一个更好的方法来覆盖,但这是我要去做这个工作的概念

首先,您需要知道没有指定任何源的绑定(就像您的情况一样),使用Binding.RelativeSource的绑定和使用Binding.ElementName的绑定将不能与DataGridColumn一起工作,因为它直接派生自DependencyObject,这是不够的。基本上,为了使这些工作,目标对象的类型需要派生自FrameworkElementFrameworkContentElement,并且它应该是可视化或逻辑树的一部分(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行,因为a)它不是必要的,b)它会给你很多麻烦,当使用你的控制(例如绑定DataGrid.ItemsSource到一个视图模型属性将不工作,因为它通常做)。