Интересный вопрос. Я написал компонент DockPanelWithOverlay, который выполняет эту работу:
Я выбрал CustomControl, потому что хотел наследовать Panel. Но у Panel нет шаблона, который можно изменить. Итак, я написал настраиваемый элемент управления, наследующий элемент управления с настраиваемым шаблоном, но пользовательский элемент управления, я думаю, отлично работал бы (я не пытался быть честным)
Edit UserControl не так хорош, потому что он наследует ContentControl. Таким образом, у него может быть только один дочерний элемент.
Цель DockPanelWithOverlay - иметь много детей. Поэтому я считаю, что UserControl - не самое лучшее наследование, как это часто бывает. UserControl лучше, если вы хотите предоставить некоторый контент в xaml, в основном статический, не настраиваемый пользователем элемента управления.
Конец редактирования
Чтобы организовать контент внутри tempalte, я использовал сетку.
Порядок двух компонентов имеет значение. Это порядок рисования.
Grid позволяет разместить два компонента в одном месте:
Внутри будет элемент управления Overlay и базовая DockPanel.
DockPanelWithOverlay
.. |
.. | -ControlTemplate
...... |
...... | -Grid
.......... |
.......... | --DockPanel
.......... | --OverlayControl
Имея шаблон, проще сделать некоторую привязку из DockPanelWithOverlay к свойствам элементов управления шаблона. (Чтобы создать CustomControl, создайте проект библиотеки пользовательских элементов управления WPFC)
Выдержка из themes \ generic.xaml в библиотеке:
<Style TargetType="{x:Type local:DockPanelWithOverlay}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DockPanelWithOverlay}">
<!-- the grid allows to put two components at the same place -->
<Grid >
<DockPanel x:Name="dockPanel" />
<ContentControl x:Name="overlayControl" Visibility="{TemplateBinding OverlayVisibility}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Наследование управления позволяет использовать шаблон для создания небольшой иерархии UIElements.
Чтобы разрешить привязку, необходимо добавить некоторые свойства зависимостей:
- Наложение для предоставления некоторых элементов UIElements или строки для наложения содержимого
- OverlayVisibility для скрытия / отображения наложения
Вот код для DockPanelWithOverlay:
(обратите внимание на OnApplytemplate, вызываемый сразу после вызова компонентов шаблонов)
// Children is the property that will be valued with the content inside the tag of the control
[ContentProperty("Children")]
public class DockPanelWithOverlay : Control
{
static DockPanelWithOverlay()
{
// Associate the control with its template in themes/generic.xaml
DefaultStyleKeyProperty.OverrideMetadata(typeof(DockPanelWithOverlay), new FrameworkPropertyMetadata(typeof(DockPanelWithOverlay)));
}
public DockPanelWithOverlay()
{
Children = new UIElementCollection(this, this);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// once the template is instanciated, the dockPanel and overlayCOntrol can be found from the template
// and the children of DockPanelWithOverlay can be put in the DockPanel
var dockPanel = this.GetTemplateChild("dockPanel") as DockPanel;
if (dockPanel != null)
for (int i = 0; i < Children.Count; )
{
UIElement elt = Children[0];
Children.RemoveAt(0);
dockPanel.Children.Add(elt);
}
}
// Here is the property to show or not the overlay
public Visibility OverlayVisibility
{
get { return (Visibility)GetValue(OverlayVisibilityProperty); }
set { SetValue(OverlayVisibilityProperty, value); }
}
// Here is the overlay. Tipically it could be a Texblock,
// or like in our example a Grid holding a TextBlock so that we could put a semi transparent backround
public Object Overlay
{
get { return (Object)GetValue(OverlayProperty); }
set { SetValue(OverlayProperty, value); }
}
// Using a DependencyProperty as the backing store for OverlayProperty.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty OverlayProperty =
DependencyProperty.Register("Overlay", typeof(Object), typeof(DockPanelWithOverlay), new PropertyMetadata(null));
public static readonly DependencyProperty OverlayVisibilityProperty =
DependencyProperty.Register("OverlayVisibility", typeof(Visibility), typeof(DockPanelWithOverlay), new PropertyMetadata(Visibility.Visible));
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public UIElementCollection Children
{
get { return (UIElementCollection)GetValue(ChildrenProperty); }
set { SetValue(ChildrenProperty, value); }
}
public static readonly DependencyProperty ChildrenProperty =
DependencyProperty.Register("Children", typeof(UIElementCollection), typeof(DockPanelWithOverlay), new PropertyMetadata(null));
}
Используя DockPanelWithOverlay:
<lib:DockPanelWithOverlay x:Name="dockPanelWithOverlay1"
OverlayVisibility="Visible"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Button Content="Top" Height="50" DockPanel.Dock="Top" Background="Red"/>
<Button Content="Bottom" Height="50" DockPanel.Dock="Bottom" Background="Yellow"/>
<Button Content="Left" Width="50" DockPanel.Dock="Left" Background="Pink"/>
<Button Content="Right" Width="50" DockPanel.Dock="Right" Background="Bisque"/>
<Button Content="Center" Background="Azure"/>
<lib:DockPanelWithOverlay.Overlay>
<Grid Background="#80404080">
<TextBlock Text="Overlay" FontSize="80" Foreground="#FF444444" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-15"/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
</Grid>
</lib:DockPanelWithOverlay.Overlay>
</lib:DockPanelWithOverlay>
Оверлей можно легко включить или отключить привязку, например, с помощью свойства CheckBox.IsChecked.
Вот полный рабочий код: http://1drv.ms/1NfCl9z
Думаю, это действительно ответ на ваш вопрос. С Уважением
person
Emmanuel DURIN
schedule
09.10.2015