WPF Макет пользовательского контроля в режиме запуска - PullRequest
6 голосов
/ 16 ноября 2009

В WPF я хочу создать окно, которое выглядит следующим образом:

Приложение с пользовательскими элементами управления http://www.freeimagehosting.net/uploads/86209e1a87.png

На экране находятся четыре пользовательских элемента управления, # 1, 2, 3, 4. Как видите, пользовательский элемент управления 2 должен отображаться не как прямоугольник, а как встроенный.

Если бы это был документооборот WPF:

  • 1, 3, 4 будет абзац (бокс)
  • 2 пробега (встраивание)

Причина в том, что 2 можно использовать в другой форме, не разбивая на 3.

У вас есть идеи, как это сделать правильно?

Некоторая идея уже пришла в голову:

  • 2 - это обычный пользовательский элемент управления (заниматься боксом). Когда помещено в окно, 2, 3, 4 размещаются на холсте, используя там Z-порядок и маржа тонны контроля как они отображаются
  • 2 имеет уже отформатированную сетку, чтобы она могла принимать 3 и 4 в качестве ContentControl, и мы внедряем их через Xaml или код позади
  • 2 выставляет основную сетку как свойство, и через добротность Attached Property мы добавляем данные для 3 и 4
  • Мы создаем наш собственный элемент управления макетом и реализуем методы Arrange и Measure для создания макета, выполняющего функцию Run

И некоторые другие, которые не так чисты ...

Есть мысли?

Спасибо,

Patrick

Ответы [ 7 ]

1 голос
/ 17 ноября 2009

Я удивлен, что никто еще не предложил с использованием фактического FlowDocument , чтобы выложить ваш пользовательский интерфейс.

Я использовал FlowDocument прежде, чтобы достигнуть сложных аранжировок. Он работает довольно хорошо, за исключением того, что некоторые свойства наследуются (например, TextElement.FontSize). Это не сложно обойти.

В вашем случае просто разбейте # 2 на отдельный UserControl для каждого раздела, а внутри FlowDocument используйте InlineUIContainer, чтобы обернуть каждый раздел.

<Window>
  <DockPanel>
    ... toolbars, etc ...

    <FlowDocumentScrollViewer ...>
      <FlowDocument>
        ...
         <InlineUIContainer>
           <my:PartialNumberTwo DataContext="{Binding ...}" />
         </InlineUIContainer>
        ...

Конечно, существуют ограничения на то, что может делать FlowDocument, поэтому он может не работать в вашем сценарии.

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

Такая панель будет использоваться так:

<Grid ...>
  ... RowDefinitions, ColumnDefinitions ...

  <panels:WrapIntoRemainingSpacePanel RowSpan="4" ColumnSpan="3"> <!-- fill whole grid -->
    <my:Control2Part1 />
    <my:Control2Part2 />
    <my:Control2Part3 />
    <my:Control2Part4 />
 </panels:WrapIntoRemainingSpacePanel>

 <my:Control1 Grid.Row="0" Grid.ColumnSpan="3" />
 <my:Control3 Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" />
 <my:Control4 Grid.Row="3" Grid.RowSpan="2" />

Эта панель будет реализована следующим образом:

  1. В ArrangeOverride запланируйте обратный вызов Dispatcher.BeginInvoke для выполнения фактического упорядочивания и создания отчета в полном размере
  2. В обратном вызове получите прямоугольники, представляющие ограничивающие рамки всех моих братьев и сестер в координатном пространстве моего родителя.
  3. Сортировать координаты Y (сверху и снизу) всех размещенных прямоугольников
  4. Поместите каждого дочернего элемента, найдя первую координату Y в отсортированном списке, в котором где-то есть горизонтальное пространство для содержимого, и поместив его как можно левее
  5. Мониторинг VisualTransform братьев и сестер для изменений, если любой вызов InvalidateArrange ()
1 голос
/ 16 ноября 2009

Для меня, чтобы упростить жизнь вашему дизайнеру, я бы предложил вам решение ContentControl.

Таким образом, ваш дизайнер может легко добавить свои элементы управления и для вас, просто сделайте свой Usercontrol # 2 достаточно умным, чтобы правильно отобразить ваш макет.

1 голос
/ 16 ноября 2009

Я предлагаю вам разделить ваш Control # 2 на 3 или 4 более конкретных UserControl. Затем загрузите # 2, # 3, # 4 внутри WrapPanel. Проверьте эту ссылку : макет UserControl для реализации стратегии Arrange and Mesure с интеллектуальной панелью переноса.

1 голос
/ 16 ноября 2009

Я думаю, что ваша форма неправильно разбита, ИМО.

Область 2 не должна включать нижнюю часть, которую вы описываете, которую вы хотите иметь "встроенной".

Он должен отделяться (насколько это касается макета) и, вероятно, помещаться в сетку из 2 столбцов и 2 строк вместе с областью 3 и областью 4. В этом случае область 3 должна иметь размер строки в 2 *.

В этом случае XAML, на самом деле, будет довольно чистым, если сделать это таким образом.

Это может выглядеть примерно так:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <uC:Area1 Grid.Row="0"><!-- Area Control here --></uC:Area1>
    <uC:Area2 Grid.Row="1"><!-- Area Control here --></uC:Area2>

    <Grid Grid.Row="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <uC:AreaDuree Grid.Row="0" Grid.Column="0">
            <!-- Area Control here -->
        </uC:AreaDuree>

        <uC:Area4 Grid.Row="1" Grid.Column="0">
            <!-- Area Control here -->
        </uC:Area4>

        <uC:Area3 Grid.RowSpan="2" Grid.Column="1">
            <!-- Area Control here -->
        </uC:Area3>                        

    </Grid>

</Grid>
0 голосов
/ 19 ноября 2009

Это 1 большая Сетка, с 3 рядами и 2 столбцами. Каждая зона этой сетки содержит сетку, которая может получать ваши пользовательские элементы управления. Таким образом, сетке №3 просто нужно, чтобы ее верхнее поле было установлено на -75. Он будет перекрывать сетку № 2, если ее поместить в xaml. Тогда вам просто нужно заблокировать столбцы и строки в зависимости от того, как вы хотите, чтобы он реагировал.

<Grid x:Name="LayoutRoot">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="0.55*"/>
        <ColumnDefinition Width="0.45*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="0.363*"/>
        <RowDefinition Height="0.369*"/>
        <RowDefinition Height="0.268*"/>
    </Grid.RowDefinitions>
    <Grid Grid.ColumnSpan="2" Background="#FF48C5D0"/>
    <Grid Margin="1,0,0,0" Grid.ColumnSpan="2" Grid.Row="1" Background="#FFD2A268"/>
    <Grid Margin="1,0,0,0" Grid.Row="2" Background="#FFB7F075"/>
    <Grid Grid.Column="1" Grid.Row="2" Background="#FFB129EC" Margin="0,-75,0,0"/>
</Grid>

Мартин Ламонтань

0 голосов
/ 17 ноября 2009

Я думаю, что это простая сетка, "хитрость" в том, что совершенно нормально иметь одну контрольную крышку на другую - WPF всегда будет отображать их в одном и том же порядке:

Я использовал Height = "Auto" для всех строк сетки, в зависимости от того, как настроены пользовательские элементы управления, вам может потребоваться указать реальную высоту, чтобы они правильно выстроились в линию.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <uc:UserControl1 Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"/>
    <uc:UserControl2 Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Grid.RowSpan="2"/>
    <uc:UserControl3 Grid.Row="2" Grid.Column="1" Grid.RowSpan="2"/>
    <uc:UserControl4 Grid.Row="3" Grid.Column="0"/>
<Grid>
0 голосов
/ 16 ноября 2009

Можно подумать о том, чтобы иметь # 3 и # 4 как часть пользовательского элемента управления # 2, тогда все становится проще для макета. Сетка верхнего уровня выкладывает # 1 и # 2

См. Второй пользовательский макет управления. И все это сетка с * размером, так что он получает размер в соответствии с размером окна.

альтернативный текст http://img5.imageshack.us/img5/4419/40506576.jpg

...