1

I want to change the Margin of a single object (well, maybe two) in a large ControlTemplate that is deep within an Infragistics xamDataGrid. Is it possible to do this without creating a duplicate of the entire template?

Unfortunately I can't just use this FindChild() method I found on StackOverflow because the template I want to change represents a column header. FindChild() can't help modify the template, only the instantiated controls. So I can use that method to find and modify the first column header, but the other columns are not affected. I could modify the code to find all of the headers, but if I ever decide to modify the set of columns, I expect that any new columns would be instantiated from the original template and would not include the desired change.

If what I want to do is impossible, that's okay, I just want someone to tell me so :)

Community
  • 1
  • 1
Qwertie
  • 16,354
  • 20
  • 105
  • 148
  • Have you tried naming the individual headers? – N_A Nov 18 '11 at 19:45
  • I don't follow you. Infragistics Field objects (within a FieldLayout) control the column headers and rows; they have a Name property which is actually what Infragistics uses for data binding. But this is irrelevant to the question. – Qwertie Nov 18 '11 at 20:12
  • Ah, I misunderstood. I thought you had control of the template. – N_A Nov 18 '11 at 20:14
  • Nah, the template is defined within an Infragistics DLL (Infragistics is a company that makes controls). They do, however, provide copies of their XAML so that one can duplicate their templates. It just seems yucky to duplicate the whole template to change one thing, because this means I have to "bake" the theme into my app (the control has several visual "themes" to choose from) and the copy could break between different versions of the 3rd-party library. Or so I imagine. – Qwertie Nov 18 '11 at 21:29

3 Answers3

1

Saying that something is not possible is always hard as there are many ways to approach a problem and one would need to know all of them.

Well, in this case i would say that modifying a template might be possible in theory using a lot of reflection meddling with internal components whose implementation one should not rely on, so in practice it probably is impossible.

Unless the template is defined in code (which is unlikely) you will end up with a ControlTemplate that has no VisualTree but a Template which is a TemplateContent, about which the documentation has to say the following:

This class has no public API in .NET Framework 4.

As mentioned you could try to modify this using reflection but i would not recommend doing so at all and i cannot give you any direction on it as i did not try to do that so far.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • I'm not sure how I "end up" with a ControlTemplate without a VisualTree, but if you're a WPF expert, I'll assume this endeavor is impossible by conventional means. – Qwertie Nov 18 '11 at 21:33
  • @Qwertie: By that i meant that the `VisualTree` property of the template object will not be set. You can use said property to define templates in code behind using [`FrameworkElementFactories`](http://msdn.microsoft.com/en-us/library/system.windows.frameworkelementfactory.aspx), this is deprecated though. If the template is parsed from XAML the property will be null and `Template` will be set instead. Calling me an expert is probably an overstatement, i have tried to modify templates before and i never got far but of course there still might be something i am overlooking. – H.B. Nov 18 '11 at 21:50
1

If margin is the only difference between the control templates then I suppose you could write an attached property to deal with this say 'AttachedMargin'. On the control give AttachedMargin a value, and use this value inside your Control Template.

Example code:

AttachedMargin Attached property:

using System.Windows;

namespace MarginProject
{
    public class AttachedProperties
    {
        public static Thickness GetAttchedMargin(DependencyObject obj)
        {
            return (Thickness)obj.GetValue(AttchedMarginProperty);
        }

        public static void SetAttchedMargin(DependencyObject obj, Thickness value)
        {
            obj.SetValue(AttchedMarginProperty, value);
        }

        // Using a DependencyProperty as the backing store for AttchedMargin.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AttchedMarginProperty =
            DependencyProperty.RegisterAttached("AttchedMargin", typeof(Thickness), typeof(AttachedProperties), new UIPropertyMetadata(new Thickness(0)));       
    }
}

XAML:

<Window x:Class="MarginProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:attprops="clr-namespace:MarginProject"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ControlTemplate x:Key="SimpleButton"  TargetType="{x:Type Button}">
            <Grid>
                <Border Name="BackgroundBorder" Background="{TemplateBinding Background}" BorderBrush="Black" BorderThickness="0,0,1,1" CornerRadius="4"  />
                <Border Name="HighlightBorder" BorderBrush="White" BorderThickness="1,1,0,0" CornerRadius="4" />
                <TextBlock  VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Content}" Margin="{Binding Path=(attprops:AttachedProperties.AttchedMargin), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" />
            </Grid>
        </ControlTemplate>

        <Style TargetType="{x:Type Button}">
            <Setter Property="Width" Value="100" />
            <Setter Property="Height" Value="30" />
            <Setter Property="Background" Value="LightBlue" />
            <Setter Property="Template" Value="{StaticResource SimpleButton}" />
        </Style>

    </Window.Resources>
    <StackPanel>
        <Button Content="Hello WPF!" attprops:AttachedProperties.AttchedMargin="25,0,0,0" />
        <Button Content="Hello WPF!" />
    </StackPanel>

</Window>
Danield
  • 121,619
  • 37
  • 226
  • 255
0

Not sure if this hits everything you need, but, for the style property, you can use the BasedOnproperty when declaring a style and use the style of the control template.

<Style x:Key="Style1">
  <Setter Property="Control.Background" Value="Yellow"/>
</Style>

<Style x:Key="Style2" BasedOn="{StaticResource Style1}">
  <Setter Property="Control.Foreground" Value="Blue"/>
</Style>
N_A
  • 19,799
  • 4
  • 52
  • 98