吃我的蛋糕也吃它:绑定容器及其内容

Have my cake and eat it too: Binding a Container and It's Contents

我有一个自定义控件 Cake,它包含两个名为 Slice 和 Filling 的 DependencyProperties。 如何创建既能让我访问 Slice,又能让我设计 slice 的样式?

<Style TargetType={x:Type local:Cake}>
    //I don't like setting DataContext Here
    <Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource Self}}/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType={x:Type local:Cake}>
                <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">                        

                    //This is how I display a slice
                    <ContentPresenter Content={Binding Slice}/>

                    //This is how cake decorations are displayed
                    <ItemsPresenter/> 

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Slice">
        <Setter.Value>

            //Design Slice Here - it's easy to override when I want  
            <Slice Filling={Binding Filling}> // it's just in a setter.

        </Setter.Value>
    </Setter>
    <Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource Self}}/>
</Style>

我试过的选项:

我基本上希望每个蛋糕都有一片,并且能够使用

进行设置
<Cake.Slice>
    <DockPanel>
       <Rectangle Background= “Blue”/>
       <Rectangle Background= “Blue”/>
       <Rectangle Background=“{Binding Filling}”/>
    </DockPanel>
</Cake.Slice>

同时还赋予其默认外观。

编辑: Apparent 只有我的风格行得通,前提是我引用了 Cake.dll 而不是 Cake 项目。为什么会这样?

这可能不是您所需要的,但我希望它能为您提供实现该目标的指导。

首先,您不需要将 DataContext 设置为控件本身,您可以使用 {TemplateBinding Slice} 从 Cake 的 ControlTemplate 绑定到 Cake 控件的属性(填充和切片),即只是 {Binding Slice, RelativeSource={RelativeSource TemplatedParent}} 的快捷方式(因此您可以使用其中之一)。

这将是您的控件的简化版本,因为我不知道您的 ControlTemplate 中的 ItemPresenter 应该显示哪些项目,或者您的 Slice 和 Filling 属性的类型是什么。在这个例子中 Filling 是 SolidColorBrush,Slice 是 Style。该样式应用于 Cake 的 ControlTemplate 中的 ContentControl,因此您可以为切片预定义样式,并应用您选择的填充(如果您的切片 属性 有不同的用途,您可以例如介绍另一个 属性 称为 SliceStyle)。

蛋糕控:

public class Cake : Control
{
    static Cake()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(Cake),
            new FrameworkPropertyMetadata(typeof(Cake)));
    }

    public SolidColorBrush Filling
    {
        get { return (SolidColorBrush)GetValue(FillingProperty); }
        set { SetValue(FillingProperty, value); }
    }

    public static readonly DependencyProperty FillingProperty =
        DependencyProperty.Register(
            "Filling",
            typeof(SolidColorBrush),
            typeof(Cake),
            new PropertyMetadata(Brushes.Transparent));

    public Style Slice
    {
        get { return (Style)GetValue(SliceProperty); }
        set { SetValue(SliceProperty, value); }
    }

    public static readonly DependencyProperty SliceProperty =
        DependencyProperty.Register(
            "Slice",
            typeof(Style),
            typeof(Cake),
            new PropertyMetadata(null));
}

默认样式(Generic.xaml):

<Style TargetType="{x:Type local:Cake}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:Cake}">
                <ContentControl Width="{TemplateBinding Width}"
                                Height="{TemplateBinding Height}"
                                Style="{TemplateBinding Slice}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

不同的切片样式(这些是为 ContentControl 设置 ControlTemplate,因此您不会在问题中遇到第 3 个问题):

<Window.Resources>
    <Style x:Key="TwoLayeredSlice" TargetType="{x:Type ContentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Rectangle Fill="{Binding Filling,
                            RelativeSource={RelativeSource AncestorType={x:Type local:Cake}}}"/>
                        <Rectangle Fill="Brown"
                                   Grid.Row="1"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="FourLayeredSlice" TargetType="{x:Type ContentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Rectangle Fill="{Binding Filling,
                            RelativeSource={RelativeSource AncestorType={x:Type local:Cake}}}"/>
                        <Rectangle Fill="Brown"
                                   Grid.Row="1"/>
                        <Rectangle Fill="{Binding Filling,
                            RelativeSource={RelativeSource AncestorType={x:Type local:Cake}}}"
                                   Grid.Row="2"/>
                        <Rectangle Fill="Brown"
                                   Grid.Row="3"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

以及正在使用的控件:

<Grid Background="Gray">
    <local:Cake Width="200"
                Height="100"
                HorizontalAlignment="Left"
                Filling="Gold"
                Slice="{StaticResource TwoLayeredSlice}"/>
    <local:Cake Width="200"
                Height="100"
                HorizontalAlignment="Center"
                Filling="Pink"
                Slice="{StaticResource FourLayeredSlice}"/>
    <local:Cake Width="200"
                Height="100"
                HorizontalAlignment="Right"
                Filling="Blue"
                Slice="{StaticResource FourLayeredSlice}"/>
</Grid>

祝你胃口大开!