Представьте конструктор форм с наложенной сеткой, которая представляет координаты на плоскости. Я пытаюсь связать свойства наложения сетки с Canvas
в пользовательском ItemsControl
.
Сетка создается с помощью файла VisualBrush
. Viewbox
и Viewport
VisualBrush
привязаны к Rect
в коде, а также Height
и Width
Rectangle
используются для отображения плитки сетки. Однако, когда отображается элемент управления, плитки сетки кажутся «бесконечно маленькими» (сетка просто серая) в том смысле, что, если я увеличу сетку, программа в конечном итоге просто остановится, не в силах ее отобразить. Очевидно, это не тот эффект, которого я добиваюсь.
<Style TargetType="{x:Type Controls:FormControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Controls:FormControl}">
<Border Background="White"
BorderBrush="Black"
BorderThickness="1"
Padding="49">
<Grid Height="{TemplateBinding CanvasHeight}"
Width="{TemplateBinding CanvasWidth}">
<Grid.Background>
<!--"0,0,6,11.3266666666667"-->
<VisualBrush TileMode="Tile"
Viewbox="{TemplateBinding GridUnitViewbox}"
ViewboxUnits="Absolute"
Viewport="{TemplateBinding GridUnitViewbox}"
ViewportUnits="Absolute">
<VisualBrush.Visual>
<Rectangle Height="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox.Height}"
HorizontalAlignment="Left"
Opacity="{TemplateBinding GridOpacity}"
Stroke="Black"
StrokeThickness=".1"
VerticalAlignment="Top"
Width="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox.Width}" />
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
<ItemsPresenter />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="Controls:FormControlItem">
<Setter Property="Canvas.Left"
Value="{Binding Path=X}" />
<Setter Property="Canvas.Top"
Value="{Binding Path=Y}" />
</Style>
</Setter.Value>
</Setter>
</Style>
Любая идея, что я делаю неправильно здесь. Спасибо.
РЕДАКТИРОВАТЬ: Может быть, немного больше информации о том, что я делаю, может поместить это в лучший контекст. Я работаю в компании, занимающейся программным обеспечением для расчета налогов, и в настоящее время наш отдел форм создает замещающие формы, используя разметку, которая была написана для нашего продукта миллион лет назад. Создавать формы таким образом немного громоздко, поэтому я разрабатываю для них визуальный «Конструктор форм», который будет больше похож на WYSIWYG и переводит содержимое конструктора в разметку. Что ж, IRS очень беспокоится о том, что все в форме находится ТОЧНО там, где оно было в оригинале, поэтому существует очень свободный стандарт, согласно которому «наложение сетки» может быть размещено поверх формы, чтобы определить, куда нужно идти; по сути своего рода координатная плоскость.
FormControl
по сути является визуальным представлением одной из этих замещающих форм, которую будет создавать один из дизайнеров форм.
CanvasWidth
и CanvasHeight
являются оболочками CLR для свойств зависимостей. Им присваиваются значения в OnApplyTemplate()
путем умножения размеров GridUnitViewbox
на то, сколько плиток сетки должно быть в наложении сетки, т.е. сетка 78x63 в большинстве случаев.
Я думаю, что имена CanvasWidth
и CanvasHeight
могут немного вводить в заблуждение, поскольку они относятся не к элементу управления Canvas
, а к Grid
, в котором находится Canvas
(вероятно, нужно изменить соглашение об именах). Тем не менее, CanvasHeight
, CanvasWidth
и GridUnitViewbox
не зависят от каких-либо свойств элемента управления, а скорее зависят от вычислений, которые выполняются в OnApplyTemplate()
.
public static readonly DependencyProperty GridUnitViewboxProperty =
DependencyProperty.Register("GridUnitViewbox", typeof(Rect), typeof(FormControl),
new FrameworkPropertyMetadata(new Rect(0, 0, 6, 11.3266666666667),
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsParentMeasure));
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
FormattedText formattedText = new FormattedText(
"X",
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Courier New"),
10,
Brushes.Black);
this.GridUnitViewbox = new Rect(0, 0, formattedText.WidthIncludingTrailingWhitespace, formattedText.Height);
if (this.PageLayout == PageLayoutType.Landscape)
{
this.CanvasHeight = this.GridUnitViewbox.Height * 48.0;
this.CanvasWidth = this.GridUnitViewbox.Width * 109.0;
}
if (this.PageLayout == PageLayoutType.Portrait)
{
this.CanvasHeight = this.GridUnitViewbox.Height * 63.0;
this.CanvasWidth = this.GridUnitViewbox.Width * 78.0;
}
}
Элемент управления Grid
на самом деле делает именно то, что я хочу. Это VisualBrush
и Rectangle
внутри, которые либо неправильно связываются, либо не обновляются должным образом. Комментарий прямо под <Grid.Background>
был жестко закодированным проверочным значением, которое я использовал для VisualBrush
Viewbox
и Viewport
, а также для измерений Rectangle
до того, как я привязал значения, и это визуально дало именно то, что я собирался. Я также подтвердил, что 6 и 11.3266666666667 на самом деле являются значениями для измерений GridUnitViewbox
во время выполнения.
Однако у меня есть ощущение, что привязка создает «0,0,0,0», потому что наложение сетки — это просто серый оттенок, который поглощает огромное количество ресурсов; фактически блокирует программу, если вы увеличиваете ее масштаб. Как видите, в коде я попытался добавить AffectsMeasure
и AffectsParentMeasure
к параметрам метаданных свойства зависимости в надежде, что, возможно, пользовательский интерфейс не обновлялся должным образом после обновления размеров GridUnitViewbox
, но я ошибся. Я не уверен, что еще это может быть.