带有展开的UWP派生按钮:在样式内绑定



General:在自定义控件的Style中,是否可以从<Setter Property="MyFirstProperty">中绑定到另一个DependencyProperty(例如MySecondProperty)值?

为什么?要完成以下操作:

1)。派生一些MyButton : Button控件,它有一个附加的List<string> FlyoutSource依赖属性。

2)。定义一个MyButtonStyle,它有一个<Setter Property="Flyout">元素,定义Button.Flyout属性(从MyButton : Button开始)。

Flyout将包含ListView, ItemsSource必须绑定到MyButton.FlyoutSource

<Style TargetType="local:MyButton" x:Key="MyButtonStyle">
    <Setter Property="Background" Value="Green"/>
    <Setter Property="Flyout">
        <Setter.Value>
            <Flyout>
                <!-- &&&&&&& THE FOLLOWING LINE DOES NOT WORK PROPERLY &&&&&&& -->
                <ListView ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=FlyoutSource}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding}"/>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </Flyout>
        </Setter.Value>
    </Setter>
</Style>

我想如何使用解决方案:

<local:MyButton 
    FlyoutSource="{x:Bind FlyoutSourceList, Mode=TwoWay}"
    Style="{StaticResource MyButtonStyle}">
</local:MyButton
更多细节:MyButton类:
public class MyButton : Button
{
    public MyButton()
    {
        this.DefaultStyleKey = typeof(Button);
    }
    public static DependencyProperty FlyoutSourceProperty = DependencyProperty.Register(
    "FlyoutSource", typeof(List<string>), typeof(MyButton),
    new PropertyMetadata(null, new PropertyChangedCallback(OnFlyoutSourceChanged)));
    public List<string> FlyoutSource
    {
        get { return (List<string>)GetValue(FlyoutSourceProperty); }
        set { SetValue(FlyoutSourceProperty, value); }
    }
    public static void OnFlyoutSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine("");
    }
}

您实际上不需要子类化Button来实现此功能,只需将FlyoutSource设置为附加属性。

你不能在这里使用RelativeSource模式TemplatedParent,因为它不在一个ControlTemplate中。

显示内容从附加元素获取信息的唯一方法似乎是通过DataContext继承。我只能想到这个,但它涉及到很多绑定体操。我不推荐。

public class ViewProps
{
    public static object GetFlyoutListSource(DependencyObject obj)
    {
        return (object)obj.GetValue(FlyoutListSourceProperty);
    }
    public static void SetFlyoutListSource(DependencyObject obj, object value)
    {
        obj.SetValue(FlyoutListSourceProperty, value);
    }
    public static readonly DependencyProperty FlyoutListSourceProperty =
        DependencyProperty.RegisterAttached("FlyoutListSource", typeof(object), typeof(ViewProps), new PropertyMetadata(null));
}
<Grid x:Name="MyGrid">
    <Grid.Resources>
        <Style x:Key="FlyoutButton" TargetType="Button">
            <Setter Property="Flyout">
                <Setter.Value>
                    <Flyout>
                        <ListView ItemsSource="{Binding (local:ViewProps.FlyoutListSource)}"/>
                    </Flyout>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <Button
        Style="{StaticResource FlyoutButton}"
        Content="Button"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        local:ViewProps.FlyoutListSource="{Binding ElementName=MyGrid, Path=DataContext.ItemsSource}"/>
</Grid>

如果你想子类化Button,那么你可以这样做。

ListFlyoutButton.cs

public sealed class ListFlyoutButton : Button
{
    public object ItemsSource
    {
        get { return (object)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(object), typeof(ListFlyoutButton), new PropertyMetadata(null));
    public ListFlyoutButton()
    {
        this.DefaultStyleKey = typeof(ListFlyoutButton);
    }
    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        ((FrameworkElement)((Flyout)Flyout).Content).DataContext = this;
    }
}

主题 Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="***">
    <Style TargetType="local:ListFlyoutButton">
        <Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
        <Setter Property="Foreground" Value="{ThemeResource ButtonForeground}" />
        <Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}" />
        <Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
        <Setter Property="Padding" Value="8,4,8,4" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
        <Setter Property="FontWeight" Value="Normal" />
        <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
        <Setter Property="UseSystemFocusVisuals" Value="True" />
        <Setter Property="FocusVisualMargin" Value="-3" />
        <Setter Property="Flyout">
            <Setter.Value>
                <Flyout>
                    <ListView ItemsSource="{Binding ItemsSource}"/>
                </Flyout>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ListFlyoutButton">
                    <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ContentPresenter x:Name="ContentPresenter"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Content="{TemplateBinding Content}"
                                ContentTransitions="{TemplateBinding ContentTransitions}"
                                ContentTemplate="{TemplateBinding ContentTemplate}"
                                Padding="{TemplateBinding Padding}"
                                HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                AutomationProperties.AccessibilityView="Raw" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

MainPage.xaml

<local:ListFlyoutButton Content="Button" ItemsSource="{Binding Items}"/>

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        DataContext = new
        {
            Items = new[] { "Apple", "Banana" },
        };
    }
}

如果我们不需要复制整个默认的Button样式就好了

最新更新