Create a grid in WPF as Template programmatically
Asked Answered
N

4

11

I want to create a basic user control with a style programmatically. In this style I want to add a Grid (no problem), but I can't add column definitions to this grid.

My example code is

ControlTemplate templ = new ControlTemplate();
FrameworkElementFactory mainPanel = new FrameworkElementFactory(typeof(DockPanel));
mainPanel.SetValue(DockPanel.LastChildFillProperty, true);

FrameworkElementFactory headerPanel = new FrameworkElementFactory(typeof(StackPanel));
headerPanel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
headerPanel.SetValue(DockPanel.DockProperty, Dock.Top);
mainPanel.AppendChild(headerPanel);

FrameworkElementFactory headerImg = new FrameworkElementFactory(typeof(Image));
headerImg.SetValue(Image.MarginProperty, new Thickness(5));
headerImg.SetValue(Image.HeightProperty, 32d);
headerImg.SetBinding(Image.SourceProperty, new Binding("ElementImage") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
headerPanel.AppendChild(headerImg);

FrameworkElementFactory headerTitle = new FrameworkElementFactory(typeof(TextBlock));
headerTitle.SetValue(TextBlock.FontSizeProperty, 16d);
headerTitle.SetValue(TextBlock.VerticalAlignmentProperty, VerticalAlignment.Center);
headerTitle.SetBinding(TextBlock.TextProperty, new Binding("Title") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
headerPanel.AppendChild(headerTitle);

FrameworkElementFactory mainGrid = new FrameworkElementFactory(typeof(Grid));
FrameworkElementFactory c1 = new FrameworkElementFactory(typeof(ColumnDefinition));
c1.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Star));
FrameworkElementFactory c2 = new FrameworkElementFactory(typeof(ColumnDefinition));
c2.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto));
FrameworkElementFactory c3 = new FrameworkElementFactory(typeof(ColumnDefinition));
c3.SetValue(ColumnDefinition.WidthProperty, new GridLength(3, GridUnitType.Star));
FrameworkElementFactory colDefinitions = new FrameworkElementFactory(typeof(ColumnDefinitionCollection));
colDefinitions.AppendChild(c1);
colDefinitions.AppendChild(c2);
colDefinitions.AppendChild(c3);
mainGrid.AppendChild(colDefinitions);

mainPanel.AppendChild(mainGrid);

FrameworkElementFactory content = new FrameworkElementFactory(typeof(ContentPresenter));
content.SetBinding(ContentPresenter.ContentProperty, new Binding() { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), Path = new PropertyPath("Content") });
mainGrid.AppendChild(content);

templ.VisualTree = mainPanel;
Style mainStyle = new Style();
mainStyle.Setters.Add(new Setter(UserControl.TemplateProperty, templ));
this.Style = mainStyle;

But the creation of FrameworkElementFactory with type ColumnDefinitionCollection will throw an exception "'ColumnDefinitionCollection' type must derive from FrameworkElement, FrameworkContentElement, or Visual3D."

Who can help me?

Neritic answered 23/12, 2010 at 8:56 Comment(1)
Maybe consider using XamlReader.Load() it is prefered over FrameworkElementFactoryPutumayo
S
20

FrameworkElementFactory has some custom logic for handling the ColumnDefinitions and RowDefinitions in a Grid. For those values, you treat them like children in the factory tree, for example:

FrameworkElementFactory gridFactory = new FrameworkElementFactory(typeof(Grid));

var column1 = new FrameworkElementFactory(typeof(ColumnDefinition));
column1.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto));

var column2 = new FrameworkElementFactory(typeof(ColumnDefinition));
column2.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Star));

gridFactory.AppendChild(column1);
gridFactory.AppendChild(column2);
Stamen answered 25/10, 2011 at 14:53 Comment(0)
T
5

you can simply add column definitions like this

XAML Code:

<Grid.ColumnDefinitions>
<ColumnDefinition Height="50"/>
<ColumnDefinition Height="100"/>
<ColumnDefinition Height="*"/>
</Grid.ColumnDefinitions>

C# Code:

ColumnDefinition c = new ColumnDefinition();
c.Width = new GridLength(50, GridUnitType.Pixel);

ColumnDefinition c1 = new ColumnDefinition();
c1.Width = new GridLength(100, GridUnitType.Pixel);

ColumnDefinition c2 = new ColumnDefinition();
c2.Width = new GridLength(0, GridUnitType.Star);

grMain.ColumnDefinitions.Add(c);
grMain.ColumnDefinitions.Add(c1);
grMain.ColumnDefinitions.Add(c2);

for more check here

Transfiguration answered 23/12, 2010 at 11:40 Comment(1)
Column definitions got Width, not Height :)Pineapple
P
4
//create grid 
            var grid = new FrameworkElementFactory(typeof(Grid));

            // assign template to grid 
            CellControlTemplate.VisualTree = grid;

            // define grid's rows 
            var r = new FrameworkElementFactory(typeof(RowDefinition));
            grid.AppendChild(r);

            // define grid's columns
            var c = new FrameworkElementFactory(typeof(ColumnDefinition));
            grid.AppendChild(c);

            c = new FrameworkElementFactory(typeof(ColumnDefinition));
            c.SetValue(ColumnDefinition.WidthProperty, GridLength.Auto);
            grid.AppendChild(c);

            c = new FrameworkElementFactory(typeof(ColumnDefinition));
            c.SetValue(ColumnDefinition.WidthProperty, GridLength.Auto);
            grid.AppendChild(c);
Patter answered 7/1, 2011 at 3:20 Comment(0)
C
1

You just need to change the last part of your code. See below,

Original Code:

        colDefinitions.AppendChild(c1);
        colDefinitions.AppendChild(c2);
        colDefinitions.AppendChild(c3);
        mainGrid.AppendChild(colDefinitions);

New Code:

        mainGrid.AppendChild(c1);
        mainGrid.AppendChild(c2);
        mainGrid.AppendChild(c3);
Chop answered 31/1, 2013 at 2:35 Comment(1)
Always nice to explain why the change is needed!Sicken

© 2022 - 2024 — McMap. All rights reserved.