带有弹出窗口的UWP派生按钮:在样式中绑定

时间:2016-11-04 15:58:13

标签: xaml button uwp controltemplate flyout

对于自定义控件的Style中的

常规:,是否可以从MySecondProperty中绑定到另一个DependencyProperty(例如<Setter Property="MyFirstProperty">)值?

出于什么目的?要完成以下任务:

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("");
    }
}

1 个答案:

答案 0 :(得分:1)

您实际上并不需要将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样式,那就太好了。