我想创建一个自定义控件,它提供 DockPanel 的所有功能,但它也会公开一个辅助 Overlay ,它位于的“外部” > DockPanel中。将存在一个依赖项属性来控制覆盖面板的可见性,这样当属性设置为真/可见时,面板将显示为覆盖在DockPanel内的所有内容之上。
理想情况下,消费者可以将控件放到与普通DockPanel相同的情况下,如果没有其他更改,它的行为就像普通的DockPanel一样:
<DockPanelWithOverlay LastChildFill="True" >
<Button DockPanel.Dock="Bottom".../>
<Button DockPanel.Dock="Top".../>
<Grid>
<Grid controls.../>
</Grid>
</DockPanelWithOverlay>
但是,可以使用辅助区域来放置其他内容并在需要时调用。
<DockPanelWithOverlay LastChildFill="True" >
<Button DockPanel.Dock="Bottom".../>
<Button DockPanel.Dock="Top".../>
<Grid>
<Grid controls.../>
</Grid>
<DockPanel.Overlay>
<whatever controls for the overlay>
</DockPanel.Overlay>
</DockPanelWithOverlay>
但是,由于内容被设置了两次,因此无效?因此,为了应对,当我使用叠加时,我想我必须明确说明发生了什么?:
<DockPanelWithOverlay LastChildFill="True" >
<DockPanel.Children>
<Button DockPanel.Dock="Bottom".../>
<Button DockPanel.Dock="Top".../>
<Grid>
<Grid controls.../>
</Grid>
</DockPanel.Children>
<DockPanel.Overlay Visibility="{Binding IsVisible}">
<whatever controls for the overlay>
</DockPanel.Overlay>
</DockPanelWithOverlay>
我不完全确定解决此问题的最佳方法:是创建CustomControl还是UserControl,直接从DockPanel继承并尝试公开单独的ContentControl,或者从Panel继承并委托MeasureOverride和ArrangeOverride到DockPanel。
我该如何解决这个问题?
答案 0 :(得分:1)
有趣的问题。我编写了一个DockPanelWithOverlay组件来完成工作:
我在这里选择了CustomControl,因为我希望继承Panel。 但Panel没有可以更改的模板。 所以我用自定义模板编写了一个继承Control的Custom Control 但是我认为用户控制完全可行(我没有试图说实话)
编辑 UserControl不太好,因为它继承了ContentControl。 所以它只能有一个孩子 DockPanelWithOverlay的目标是拥有许多孩子。 所以我认为UserControl并不是最好的继承。 当你想在xaml中提供一些内容时,UserControl会更好,主要是静态的,不能由控件用户自定义。
编辑结束
为了整理tempalte中的内容,我使用了一个Grid 这两个组件的顺序很重要。 这是绘图顺序。
网格允许将两个组件放在同一个地方:
里面有Overlay控件和底层DockPanel。
DockPanelWithOverlay
.. |
.. | -ControlTemplate
...... |
...... | -Grid
.......... |
.......... | --DockPanel
.......... | --OverlayControl
使用模板更容易从DockPanelWithOverlay到模板的控件属性进行一些绑定。 (要生成CustomControl,请创建WPFCustom控件库项目)
库中的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层次结构。
必须添加一些依赖项属性才能允许绑定:
这是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
我认为这真的是你问题的答案。此致
答案 1 :(得分:0)
我建议我们应该尝试澄清你是如何看待这种方法的。我的猜测是辅助面板也是DockPanel
,并且将完全覆盖主面板。也就是说,你看到的是其中之一,但从来没有。您如何设想在两者之间切换?或许ToggleButton
?或者只是在一些Trigger
的控制之下?
我对实现的第一个想法是你似乎喜欢DockPanel
的方式?把事情搞定了,为什么要触摸布局方法呢?一种方法可能是只有一个dockpanel,而是两个子集合,您可以根据要显示的集合进行设置。或者弹出窗口中的辅助面板?
你想写这样的东西:
<DockPanelWithAlternative
AlternativeVisibility="{Binding somethingHere}" >
<TextBlock Dock.Top ... />
<TextBlock Dock.Alternative.Top ... />
</DockPanelWithAlternative>
我在想的是:
<UserControl>
<Grid>
<DockPanel x:Name="MainPanel" ZIndex="0"/>
<DockPanel x:Name="AlternativePanel" Visbility=... ZIndex="1"/>
</Grid>
</UserControl>