Создать сетку в WPF как шаблон программно
Я хочу создать основной пользовательский элемент управления с помощью стиля программно. В этом стиле я хочу добавить Grid
(нет проблем), но я не могу добавить определения столбцов к этой сетке.
Мой пример кода
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;
Но создание FrameworkElementFactory
с типом ColumnDefinitionCollection
выбросит исключение "'ColumnDefinitionCollection' type must derive from FrameworkElement, FrameworkContentElement, or Visual3D."
Кто может мне помочь?
4 ответа
FrameworkElementFactory имеет некоторую собственную логику для обработки ColumnDefinitions и RowDefinitions в Grid. Для этих значений вы рассматриваете их как дочерние в фабричном дереве, например:
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);
Вы можете просто добавить определения столбцов, как это
Код XAML:
<Grid.ColumnDefinitions>
<ColumnDefinition Height="50"/>
<ColumnDefinition Height="100"/>
<ColumnDefinition Height="*"/>
</Grid.ColumnDefinitions>
Код C#:
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);
для дополнительной проверки здесь
//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);
Вам просто нужно изменить последнюю часть вашего кода. Увидеть ниже,
Оригинальный код:
colDefinitions.AppendChild(c1);
colDefinitions.AppendChild(c2);
colDefinitions.AppendChild(c3);
mainGrid.AppendChild(colDefinitions);
Новый код:
mainGrid.AppendChild(c1);
mainGrid.AppendChild(c2);
mainGrid.AppendChild(c3);