如何将样式应用于自定义控件库中的DependencyObject

时间:2022-02-24 13:21:05

I am creating a reusable custom control, based on the TreeView. I have on the custom control created a dependency property for the columns in the control, like this:

我正在创建一个基于TreeView的可重用自定义控件。我在自定义控件上为控件中的列创建了依赖项属性,如下所示:

    public GridViewColumnCollection Columns
    {
        get { return (GridViewColumnCollection)GetValue(ColumnsProperty); }
        set { SetValue(ColumnsProperty, value); }
    }

    public static readonly DependencyProperty ColumnsProperty =
        DependencyProperty.Register("Columns", typeof(GridViewColumnCollection), typeof(TreeListView), new PropertyMetadata(new GridViewColumnCollection()));

This lets me specify a bunch of columns in XAML. The catch is that I need the first column to have a custom cell template. I was going to approach this by deriving a class from GridViewColumn, something like this:

这让我在XAML中指定了一堆列。问题是,我需要第一列具有自定义单元格模板。我打算通过从GridViewColumn派生一个类来解决这个问题,如下所示:

public class TreeGridViewColumn : GridViewColumn
{
}

and then give it the desired style in the Generic.xaml for the custom control:

然后在Generic.xaml中为自定义控件提供所需的样式:

<Style TargetType="{x:Type local:TreeGridViewColumn}">
    <Setter Property="CellTemplate">
        <Setter.Value>
            <DataTemplate>
                <Border Background="Black" /> <!-- Just for example -->
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

However the style is never applied to instances of TreeGridViewColumn. I know that I probably need to add:

但是,样式永远不会应用于TreeGridViewColumn的实例。我知道我可能需要添加:

DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeGridViewColumn), new FrameworkPropertyMetadata(typeof(TreeGridViewColumn)));

However I cannot do this, as the GridColumn base class is not a FrameworkObject, it is a DependencyObject. How can I apply a style to a descendant of a GridViewColumn defined in a Custom Control library?

但是我不能这样做,因为GridColumn基类不是FrameworkObject,它是DependencyObject。如何将样式应用于自定义控件库中定义的GridViewColumn的后代?

1 个解决方案

#1


1  

Think like this: The TreeGridViewColumn should be a dummy object holding important information for the column itself such as width and height and also for each cell under that columns header for example the cell template itself. Therefore do not try to create an FrameworkElement out of TreeGridViewColumn. Here is an example how you might end up using the TreeGridViewColumn.

这样想:TreeGridViewColumn应该是一个虚拟对象,它包含列本身的重要信息,如宽度和高度,以及该列标题下的每个单元格,例如单元格模板本身。因此,不要尝试从TreeGridViewColumn创建FrameworkElement。下面是一个如何最终使用TreeGridViewColumn的示例。

        <TreeGridViewColumn Header="First Col" Width="50">
            <TreeGridViewColumn.CellTemplate>
                <DataTemplate>
                    <Button>
                        click me
                    </Button>
                </DataTemplate>
            </TreeGridViewColumn.CellTemplate>
        </TreeGridViewColumn>

Once you ready to display the columns and cells I suggest to you to write your own custom panel which deals with the FrameworkElements by calling their Measure and Arrange methods allowing you to position columns and cells the way you want. You will end up doing alot of math inside your custom panel class. That futhermore means you will end up spending a month on programming that TreeGridView. I suggest you to take a shortcut and download the code of such a thing. There are already few TreeListViews online. Just take their dlls and see if it will work out for you

一旦你准备好显示列和单元格,我建议你编写自己的自定义面板,通过调用它们的Measure和Arrange方法处理FrameworkElements,允许你按照你想要的方式定位列和单元格。您最终会在自定义面板类中进行大量的数学运算。更进一步意味着你最终将花费一个月的时间来编程TreeGridView。我建议你走捷径并下载这样的代码。在线已经很少有TreeListViews。只需拿走他们的dll,看看它是否适合你

EDIT:

编辑:

Ok here is a suggestion how you could solve your issue. Its just a suggestion

好的,这里有一个建议如何解决你的问题。这只是一个建议

The DefaultTextColumnData class is a dummy object holding all the necessary infos like columns width, etc.

DefaultTextColumnData类是一个虚拟对象,包含所有必要的信息,如列宽等。

DataGridCellControl will be that FrameworkElement that draws the cell. Its a FrameworkElement so it will have a defined style in your generic.xaml resource dictionary.

DataGridCellControl将是绘制单元格的FrameworkElement。它是一个FrameworkElement,因此它将在generic.xaml资源字典中具有已定义的样式。

To sum up DefaultTextColumnData will hold all infos for the column itself. DataGridCellControl will be a control which might end up having 20 instances of itself in case you have 20 cells in that column.

总结一下DefaultTextColumnData将保存列本身的所有信息。 DataGridCellControl将是一个控件,如果你在该列中有20个单元格,它最终可能会有20个自身实例。

DataGridCellControl must know about its column. This is how the code of DataGridCellControl will look alike:

DataGridCellControl必须知道它的列。这就是DataGridCellControl的代码看起来很相似的方式:

class DefaultTextColumnData : DataGridColumn
{
}

class ComplexColumnData : DataGridColumn
{
}

class DataGridCellControl : Control
{
  public DataGridColumn Column
  {
    get; set;
  }

  public DataTemplate DefaultTextCellTemplate
  {
    get; set;
  }

  public override Size MeasureOverride(Size size)
  {
   ...
   if(this.Column is DefaultTextColumnData)
   {
    this.Template = this.DefaultTextCellTemplate
   }

   if(this.Column is ComplexColumnData)
   {
    this.Template = ...
   }
   ...
   return new Size(30, 30);
  }
}

DefaultTextCellTemplate will be set in your generic.xaml like this:

DefaultTextCellTemplate将在你的generic.xaml中设置如下:

<Style TargetType={x:Type DataGridCellControl}>
 <Setter Property="DefaultTextCellTemplate">
  <Setter.Value>
   <DataTemplate>
    <TextBlock Background="Black" Margin="5"/>
     ....

Thats how you set default cell template in your resource dictionary.

这就是你如何在资源字典中设置默认单元格模板。

#1


1  

Think like this: The TreeGridViewColumn should be a dummy object holding important information for the column itself such as width and height and also for each cell under that columns header for example the cell template itself. Therefore do not try to create an FrameworkElement out of TreeGridViewColumn. Here is an example how you might end up using the TreeGridViewColumn.

这样想:TreeGridViewColumn应该是一个虚拟对象,它包含列本身的重要信息,如宽度和高度,以及该列标题下的每个单元格,例如单元格模板本身。因此,不要尝试从TreeGridViewColumn创建FrameworkElement。下面是一个如何最终使用TreeGridViewColumn的示例。

        <TreeGridViewColumn Header="First Col" Width="50">
            <TreeGridViewColumn.CellTemplate>
                <DataTemplate>
                    <Button>
                        click me
                    </Button>
                </DataTemplate>
            </TreeGridViewColumn.CellTemplate>
        </TreeGridViewColumn>

Once you ready to display the columns and cells I suggest to you to write your own custom panel which deals with the FrameworkElements by calling their Measure and Arrange methods allowing you to position columns and cells the way you want. You will end up doing alot of math inside your custom panel class. That futhermore means you will end up spending a month on programming that TreeGridView. I suggest you to take a shortcut and download the code of such a thing. There are already few TreeListViews online. Just take their dlls and see if it will work out for you

一旦你准备好显示列和单元格,我建议你编写自己的自定义面板,通过调用它们的Measure和Arrange方法处理FrameworkElements,允许你按照你想要的方式定位列和单元格。您最终会在自定义面板类中进行大量的数学运算。更进一步意味着你最终将花费一个月的时间来编程TreeGridView。我建议你走捷径并下载这样的代码。在线已经很少有TreeListViews。只需拿走他们的dll,看看它是否适合你

EDIT:

编辑:

Ok here is a suggestion how you could solve your issue. Its just a suggestion

好的,这里有一个建议如何解决你的问题。这只是一个建议

The DefaultTextColumnData class is a dummy object holding all the necessary infos like columns width, etc.

DefaultTextColumnData类是一个虚拟对象,包含所有必要的信息,如列宽等。

DataGridCellControl will be that FrameworkElement that draws the cell. Its a FrameworkElement so it will have a defined style in your generic.xaml resource dictionary.

DataGridCellControl将是绘制单元格的FrameworkElement。它是一个FrameworkElement,因此它将在generic.xaml资源字典中具有已定义的样式。

To sum up DefaultTextColumnData will hold all infos for the column itself. DataGridCellControl will be a control which might end up having 20 instances of itself in case you have 20 cells in that column.

总结一下DefaultTextColumnData将保存列本身的所有信息。 DataGridCellControl将是一个控件,如果你在该列中有20个单元格,它最终可能会有20个自身实例。

DataGridCellControl must know about its column. This is how the code of DataGridCellControl will look alike:

DataGridCellControl必须知道它的列。这就是DataGridCellControl的代码看起来很相似的方式:

class DefaultTextColumnData : DataGridColumn
{
}

class ComplexColumnData : DataGridColumn
{
}

class DataGridCellControl : Control
{
  public DataGridColumn Column
  {
    get; set;
  }

  public DataTemplate DefaultTextCellTemplate
  {
    get; set;
  }

  public override Size MeasureOverride(Size size)
  {
   ...
   if(this.Column is DefaultTextColumnData)
   {
    this.Template = this.DefaultTextCellTemplate
   }

   if(this.Column is ComplexColumnData)
   {
    this.Template = ...
   }
   ...
   return new Size(30, 30);
  }
}

DefaultTextCellTemplate will be set in your generic.xaml like this:

DefaultTextCellTemplate将在你的generic.xaml中设置如下:

<Style TargetType={x:Type DataGridCellControl}>
 <Setter Property="DefaultTextCellTemplate">
  <Setter.Value>
   <DataTemplate>
    <TextBlock Background="Black" Margin="5"/>
     ....

Thats how you set default cell template in your resource dictionary.

这就是你如何在资源字典中设置默认单元格模板。