Представьте себе конструктор форм с наложением сетки, который будет представлять координаты на плоскости. Я пытаюсь привязать свойства наложения сетки к Canvas
в пользовательском ItemsControl
.
Сетка создана с использованием VisualBrush
. VisualBrush
s Viewbox
и Viewport
привязаны к 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>
Любая идея, что я здесь делаю неправильно. Спасибо.
EDIT:
Возможно, немного больше предыстории того, что я делаю, может поместить это в лучший контекст Я работаю в компании по разработке программного обеспечения для подготовки налоговых деклараций, и в настоящее время наше подразделение по созданию форм создает замещающие формы с использованием разметки, написанной для нашего продукта, как миллион лет назад. Создавать формы таким образом немного громоздко, поэтому я разрабатываю для них визуальный «Дизайнер форм», который будет больше похож на 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
, но я ошибся , Я не уверен, что еще это может быть.