Пользовательский элемент управления TemplateBinding вопрос - PullRequest
1 голос
/ 11 марта 2011

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

Ответы [ 2 ]

1 голос
/ 11 марта 2011

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

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

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

0 голосов
/ 11 марта 2011

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

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

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

...