Пользовательский элемент управления TemplateBinding вопрос

Представьте конструктор форм с наложенной сеткой, которая представляет координаты на плоскости. Я пытаюсь связать свойства наложения сетки с 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, но я ошибся. Я не уверен, что еще это может быть.


person SirBeastalot    schedule 11.03.2011    source источник
comment
вам нужно быть более конкретным и разбить вашу проблему. Сомнительно, что люди потратят время на изучение этого большого куска XAML-разметки.   -  person Stephen Chung    schedule 11.03.2011


Ответы (2)


Хорошо, на случай, если кто-то еще столкнется с подобной проблемой, я нашел обходной путь. Судя по всему, VisualBrush немного привередлив в отношении TemplateBinding. Я скорректировал XAML таким образом, и это решило проблему:

<VisualBrush TileMode="Tile"
             Viewbox="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox}"
             ViewboxUnits="Absolute"
             Viewport="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox}"
             ViewportUnits="Absolute">

Вот статья, откуда я взял информацию.

person SirBeastalot    schedule 11.03.2011

Что такое CanvasWidth и CanvasHeight? Они определены?

Кроме того, я считаю, что холст не имеет размера, если он не указан явно. Когда вы привязываетесь к нему, ширина/высота могут быть нулевыми.

Попробуйте ActualWidth и ActualHeight или холст после прохода рендеринга, чтобы увидеть, содержат ли они какие-либо значения, но, если вы их не предоставите, их нет.

person Stephen Chung    schedule 11.03.2011