Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to apply a style to a DependencyObject in a custom control library

Tags:

wpf

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:

    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:

public class TreeGridViewColumn : GridViewColumn
{
}

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

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

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?

like image 276
user3690202 Avatar asked Jan 20 '16 01:01

user3690202


People also ask

What is difference between dependency property and attached property?

Attached properties are a XAML concept, dependency properties are a WPF concept. In WPF, most UI-related attached properties on WPF types are implemented as dependency properties.

How to add dependency property WPF?

To create new dependency property we need to follow the below procedure, Declare and register dependency property. For registered property set value using SetValue method and get value using GetValue method. Write a method to handle change done on dependency property.

What is dependency property in WPF?

Windows Presentation Foundation (WPF) provides a set of services that can be used to extend the functionality of a type's property. Collectively, these services are referred to as the WPF property system. A property that's backed by the WPF property system is known as a dependency property.

What are attached properties in WPF?

Attached properties are properties which can be set on any wpf object (basically, at least a DependencyObject) via the DependencyObject. SetValue method. The purpose for this mechanism is to "attach" to other objects information needed by parent objects, not the child objects themselves. For example, the Grid.


1 Answers

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

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.

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.

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.

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

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:

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

like image 163
dev hedgehog Avatar answered Sep 22 '22 07:09

dev hedgehog