Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >[UWP]理解及扩展Expander

[UWP]理解及扩展Expander

作者头像
dino.c
发布于 2019-01-18 02:41:15
发布于 2019-01-18 02:41:15
87100
代码可运行
举报
文章被收录于专栏:dino.c的专栏dino.c的专栏
运行总次数:0
代码可运行

1. 前言

最近在自定义Expander的样式,顺便看了看它的源码。 Expander控件是一个ContentControl,它通过IsExpanded属性或者通过点击Header中的ToggleButton控制内容展开或隐藏。UWP SDK中没提供这个控件,而是在UWP Community Toolkit中 提供 。它是个教科书式的入门级控件,代码简单,虽然仍然不尽如人意,但很适合用于学习如何自定义模版化控件。

2.详解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[ContentProperty(Name = "Content")]
[TemplatePart(Name = "PART_RootGrid", Type = typeof(Grid))]
[TemplatePart(Name = "PART_ExpanderToggleButton", Type = typeof(ToggleButton))]
[TemplatePart(Name = "PART_LayoutTransformer", Type = typeof(LayoutTransformControl))]
[TemplateVisualState(Name = "Expanded", GroupName = "ExpandedStates")]
[TemplateVisualState(Name = "Collapsed", GroupName = "ExpandedStates")]
[TemplateVisualState(Name = "LeftDirection", GroupName = "ExpandDirectionStates")]
[TemplateVisualState(Name = "DownDirection", GroupName = "ExpandDirectionStates")]
[TemplateVisualState(Name = "RightDirection", GroupName = "ExpandDirectionStates")]
[TemplateVisualState(Name = "UpDirection", GroupName = "ExpandDirectionStates")]
public class Expander : ContentControl
{
    public Expander();

    public string Header { get; set; }

    public DataTemplate HeaderTemplate { get; set; }

    public bool IsExpanded { get; set; }

    public ExpandDirection ExpandDirection { get; set; }

    public event EventHandler Expanded;

    public event EventHandler Collapsed;

    public void OnExpandDirectionChanged();
    protected override void OnApplyTemplate();
    protected virtual void OnCollapsed(EventArgs args);
    protected virtual void OnExpanded(EventArgs args);
}

以上是Expander的代码定义,可以看出这个控件十分简单。本文首先对代码和XAML做个详细了解。这部分完全是面向初学者的,希望初学者通过Expander的源码学会一个基本的模板化控件应该如何构造。

2.1 Attribute

Expander定义了三种Attribute:ContentProperty、TemplatePart和TemplateVisualState。 ContentProperty表明了主要属性为Content,并且在XAML中可以将Content属性用作直接内容,即将这种代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<controls:Expander>
    <controls:Expander.Content>
        <TextBlock Text="Text" />
    </controls:Expander.Content>
</controls:Expander>

简化成如下形式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<controls:Expander>
    <TextBlock Text="Text" />
</controls:Expander>

因为Expander本来就继承自ContentControl,我很怀疑定义这个ContentProperty的必要性。(如果各位清楚这里这么做的原因请告知,谢谢。)

TemplatePart表明ControlTemplate中应该包含名为PART_ExpanderToggleButton的ToggleButton、名为PART_RootGrid的Grid及名为PART_LayoutTransformer的LayoutTransformControl。

TemplateVisualState表明ControlTempalte中应该包含名为ExpandedStates的VisualStateGroup,其中包含名为Expanded和Collapsed的两种VisualState。另外还有名为ExpandDirectionStates的VisualStateGroup,其中包含RightDirection、LeftDirection、UpDirection和DownDirection。

即使ControlTemplate中没按TemplatePart和TemplateVisualState的要求定义,Expander也不会报错,只是会缺失部分功能。

2.2 Header与HeaderTemplate

PART_ExpanderToggleButton的Content和ContentTemplate通过TemplateBinding绑定到Expander的Header和HeaderTemplate,通过HeaderTemplate,Expander的Header外观可以有一定的灵活性。

2.3 IsExpanded

Expander通过IsExpanded属性控制内容是否展开。注意这是个依赖属性,即这个属性也可以通过Binding控制。在改变IsExpanded值的同时会依次调用VisualStateManager.GoToState(this, StateContentExpanded, true);OnExpanded(EventArgs args)ExpandedVisualStateManager.GoToState(this, StateContentCollapsed, true);OnCollapsedCollapsedOnExpandedOnCollapsed都是protected virtual 函数,可以在派生类中修改行为。

许多人实现Expander时不使用IsExpanded属性,而是通过public void Expand()public void Collapse()直接控制内容展开和折叠,这种做法稍微缺乏灵活性。如PART_ExpanderToggleButton通过TwoWay Binding与IsExpanded属性关联,如果只提供public void Expand()public void Collapse()则做不到这个功能。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<ToggleButton x:Name="PART_ExpanderToggleButton" 
              IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" />

另一个常见的做法是通过代码直接控制内容是否显示,例如这样:PART_MainContent.Visibility = Visibility.Collapsed;。这样的坏处是不能在这个过程自定义动画效果或进行其它操作。Expander通过VisualStateManager实现这个功能,做到了UI和代码分离。

2.4 OnApplyTemplate

模板化控件在加载ControlTemplate后会调用OnApplyTemplate(),Expander的OnApplyTemplate()实现了通常应有的实现,即订阅事件、改变VisualState。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    if (IsExpanded)
    {
        VisualStateManager.GoToState(this, StateContentExpanded, false);
    }
    else
    {
        VisualStateManager.GoToState(this, StateContentCollapsed, false);
    }

    var button = (ToggleButton)GetTemplateChild(ExpanderToggleButtonPart);

    if (button != null)
    {
        button.KeyDown -= ExpanderToggleButtonPart_KeyDown;
        button.KeyDown += ExpanderToggleButtonPart_KeyDown;
    }

    OnExpandDirectionChanged();
}

控件在加载ControlTemplate时就需要确定它的状态,一般这时候都不会使用过渡动画。所以这里VisualStateManager.GoToState(this, StateContentExpanded, false)的参数useTransitions使用了false。 由于Template可能多次加载(实际很少发生),或者不能正确获取TemplatePart,所以使用TemplatePart前应该先判断是否为空;如果要订阅事件,应该先取消订阅。

2.5 Style

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<Style TargetType="controls:Expander">
    <Setter Property="Header" Value="Header" />
    <Setter Property="IsTabStop" Value="False" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:Expander">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="ExpandedStates">
                            <VisualState x:Name="Expanded">
                                <VisualState.Setters>
                                    <Setter Target="PART_MainContent.Visibility" Value="Visible" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Collapsed">
                                <VisualState.Setters>
                                    <Setter Target="PART_RootGrid.Background" Value="Transparent" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>

                        <VisualStateGroup x:Name="ExpandDirectionStates">
                            ....
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>

                    <Grid x:Name="PART_RootGrid" Background="{TemplateBinding Background}">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition x:Name="ColumnOne" Width="Auto" />
                            <ColumnDefinition x:Name="ColumnTwo" Width="*" />
                        </Grid.ColumnDefinitions>

                        <controls:LayoutTransformControl Grid.Row="0" Grid.RowSpan="1" Grid.Column="0" Grid.ColumnSpan="2"
                                                         x:Name="PART_LayoutTransformer"
                                                         RenderTransformOrigin="0.5,0.5">
                            <controls:LayoutTransformControl.Transform>
                                <RotateTransform x:Name="RotateLayoutTransform" Angle="0" />
                            </controls:LayoutTransformControl.Transform>

                            <ToggleButton x:Name="PART_ExpanderToggleButton" 
                                          Height="40"
                                          TabIndex="0"
                                          AutomationProperties.Name="Expand"
                                          Style="{StaticResource HeaderToggleButtonStyle}" 
                                          VerticalAlignment="Bottom" HorizontalAlignment="Stretch" 
                                          Foreground="{TemplateBinding Foreground}"
                                          Background="{TemplateBinding Background}"
                                          ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}"
                                          IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" />
                        </controls:LayoutTransformControl>

                        <ContentPresenter Grid.Row="1" Grid.RowSpan="1" Grid.Column="0" Grid.ColumnSpan="2"
                                          x:Name="PART_MainContent"
                                          Background="{TemplateBinding Background}"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          HorizontalContentAlignment="Stretch"
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          Visibility="Collapsed" />
                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如果忽略ExpandDirectionStates,Expander的Style就如以上所示十分简短(不过HeaderToggleButtonStyle有整整300行)。注意 Setter Property="IsTabStop" Value="False" 这句,对内容控件或复合控件,约定俗成都需要将IsTabStop设置成False,这是为了防止控件本身获得焦点。对Expander来说,在前一个控件上按“Tab”键,应该首先让PART_ExpanderToggleButton获得焦点。如果IsTabStop="true",Expander会获得焦点,需要再按一次“Tab”键才能让PART_ExpanderToggleButton获得焦点。

2.6 partial class

即使代码量不大,Expander还是将代码分别存放在几个partial class中,这样做的好处是让承载主要业务的文件(Expander.cs)结构更加清晰。尤其是依赖属性,一个完整的依赖属性定义可以有20行(属性标识符、属性包装器、PropertyChangedCallback等),而且其中一部分是静态的,另外一部分不是,在类中将一个依赖属性的所有部分放在一起,还是按静态、非静态的顺序存放,这也可能引起争论。

2.7 其它

虽然Expander是一个教科书式的控件,但还是有几个可以改进的地方。

最让人困扰的一点是Header居然是个String。WPF中的Expander的Header是个Object,可以方便地塞进各种东西,例如一个CheckBox或一张图片。虽然通过更改ControlTemplate或HeaderTemplate也不是不可以达到这效果,但毕竟麻烦了一些。不久前MenuItem就把Header从String类型改为Object了(Menu: changed MenuItem Header to type object),说不定以后Expander也有可能这样修改( Change Expander.Header from string to object )。

另外,在WPF中Expander派生自HeaderedContentControl,这就少写了Header、HeaderTemplate、OnHeaderChanged等一大堆代码。而Community Toolkit中每个有Header属性的控件都各自重复了这些代码。或许将来会有HeaderedContentControl这个控件吧。

PART_ExpanderToggleButton鼠标按下时Header和Content分裂的效果还挺奇怪的,这点在上一篇文章有提过( 浅谈按钮设计)。

最后,这年头连个折叠/展开动画都没有,而且还是微软出品,真是可惜(Improve Expander control (animation, color))。还好XAML扩展性确实优秀,可以自己添加这些动画。

3. 扩展

我简单地用Behavior为Expander添加了折叠/展开动画,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class PercentageToHeightBehavior : Behavior<StackPanel>
{
    /// <summary>
    /// 获取或设置ContentElement的值
    /// </summary>  
    public FrameworkElement ContentElement
    {
        get { return (FrameworkElement)GetValue(ContentElementProperty); }
        set { SetValue(ContentElementProperty, value); }
    }

      
    protected virtual void OnContentElementChanged(FrameworkElement oldValue, FrameworkElement newValue)
    {
        if (oldValue != null)
            newValue.SizeChanged -= OnContentElementSizeChanged;

        if (newValue != null)
            newValue.SizeChanged += OnContentElementSizeChanged;
    }

    private void OnContentElementSizeChanged(object sender, SizeChangedEventArgs e)
    {
        UpdateTargetHeight();
    }


    /// <summary>
    /// 获取或设置Percentage的值
    /// </summary>  
    public double Percentage
    {
        get { return (double)GetValue(PercentageProperty); }
        set { SetValue(PercentageProperty, value); }
    }

      
    protected virtual void OnPercentageChanged(double oldValue, double newValue)
    {
        UpdateTargetHeight();
    }


    public event PropertyChangedEventHandler PropertyChanged;

    private void UpdateTargetHeight()
    {
        double height = 0;
        if (ContentElement == null || ContentElement.ActualHeight == 0 || double.IsNaN(Percentage))
            height = double.NaN;
        else
            height = ContentElement.ActualHeight * Percentage;

        if (AssociatedObject != null)
            AssociatedObject.Height = height;
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<Grid>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="ExpandedStates">
            <VisualStateGroup.Transitions>
                <VisualTransition  To="Collapsed">
                    <Storyboard>
                        <DoubleAnimation Duration="0:0:0.5"
                                         To="0"
                                         Storyboard.TargetProperty="(UIElement.Opacity)"
                                         Storyboard.TargetName="PART_MainContent">
                            <DoubleAnimation.EasingFunction>
                                <CubicEase EasingMode="EaseOut" />
                            </DoubleAnimation.EasingFunction>
                        </DoubleAnimation>
                        <DoubleAnimation BeginTime="0:0:0"
                                         Duration="0:0:0.5"
                                         To="0"
                                         Storyboard.TargetProperty="(local:PercentageToHeightBehavior.Percentage)"
                                         Storyboard.TargetName="PercentageToHeightBehavior"
                                         EnableDependentAnimation="True">
                            <DoubleAnimation.EasingFunction>
                                <QuinticEase EasingMode="EaseIn" />
                            </DoubleAnimation.EasingFunction>
                        </DoubleAnimation>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                       Storyboard.TargetName="PART_MainContent">
                            <DiscreteObjectKeyFrame KeyTime="0:0:0.5">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Collapsed</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualTransition>
                <VisualTransition GeneratedDuration="0"
                                  To="Expanded">
                    <Storyboard>
                        <DoubleAnimation BeginTime="0:0:0.0"
                                         Duration="0:0:0.5"
                                         To="1"
                                         Storyboard.TargetProperty="(UIElement.Opacity)"
                                         Storyboard.TargetName="PART_MainContent">
                            <DoubleAnimation.EasingFunction>
                                <CubicEase EasingMode="EaseIn" />
                            </DoubleAnimation.EasingFunction>
                        </DoubleAnimation>
                        <DoubleAnimation BeginTime="0:0:0"
                                         Duration="0:0:0.5"
                                         To="1"
                                         Storyboard.TargetProperty="(local:PercentageToHeightBehavior.Percentage)"
                                         Storyboard.TargetName="PercentageToHeightBehavior"
                                         EnableDependentAnimation="True">
                            <DoubleAnimation.EasingFunction>
                                <QuinticEase EasingMode="EaseOut" />
                            </DoubleAnimation.EasingFunction>
                        </DoubleAnimation>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                       Storyboard.TargetName="PART_MainContent">
                            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Visible</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualTransition>
            </VisualStateGroup.Transitions>
            <VisualState x:Name="Expanded">
                <VisualState.Setters>
                    <Setter Target="PART_MainContent.(UIElement.Opacity)"
                            Value="1" />
                    <Setter Target="PercentageToHeightBehavior.(local:PercentageToHeightBehavior.Percentage)"
                            Value="1" />
                    <Setter Target="PART_MainContent.Visibility"
                            Value="Visible" />
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="Collapsed">
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ToggleButton x:Name="PART_ExpanderToggleButton"
                      Height="40"
                      TabIndex="0"
                      AutomationProperties.Name="Expand"
                      Style="{StaticResource HeaderToggleButtonStyle}"
                      VerticalAlignment="Top"
                      HorizontalAlignment="Stretch"
                      Foreground="{TemplateBinding Foreground}"
                      Background="{TemplateBinding Background}"
                      ContentTemplate="{TemplateBinding HeaderTemplate}"
                      Content="{TemplateBinding Header}"
                      IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
        <StackPanel x:Name="stackPanel"
                    Grid.Row="1">
            <Interactivity:Interaction.Behaviors>
                <local:PercentageToHeightBehavior x:Name="PercentageToHeightBehavior"
                                                  ContentElement="{Binding ElementName=PART_MainContent}"
                                                  Percentage="0" />
            </Interactivity:Interaction.Behaviors>
            <ContentPresenter x:Name="PART_MainContent"
                              Background="{TemplateBinding Background}"
                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                              HorizontalContentAlignment="Stretch"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                              Visibility="Collapsed"
                              Opacity="0" />
        </StackPanel>
    </Grid>
</Grid>

原理是把ContentPresenter放进一个StackPanel里,通过DoubleAnimation改变这个StackPanel的高度。之所以不直接改变ContentPresenter的高度是不想改变它的内容高度。另外我也改变了PART_ExpanderToggleButton的动画效果,我有点讨厌鼠标按下时文字会变模糊这点。运行效果如下:

4. 结语

写这篇文章拖了很多时间,正好2.0版本也发布了( Releases · Microsoft_UWPCommunityToolkit ),所以截图及源码有一些是不同版本的,但不影响主要内容。 如前言所说,这真的是个很好的入门级控件,很适合用于学习模板化控件。

5. 参考

Expander Control Microsoft.Toolkit.Uwp.UI.Controls.Expander

6. 源码

GitHub - ExpanderDemo 因为是在v1.5.0上写的,可能需要修改才能使用到v2.0.0上。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-09-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互
WPF有一个灵活的UI框架,用户可以轻松地使用代码控制控件的外观。例设我需要一个控件在鼠标进入的时候背景变成蓝色,我可以用下面这段代码实现:
dino.c
2019/05/23
1.9K0
[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互
[UWP]合体姿势不对的HeaderedContentControl
HeaderedContentControl是WPF中就存在的控件,这个控件的功能很简单:提供Header和Content两个属性,在UI上创建两个ContentPresenter并分别绑定到Header和Content,让这两个ContentPresenter合体组成HeaderedContentControl。
dino.c
2019/01/18
9130
[UWP]合体姿势不对的HeaderedContentControl
[UWP]理解ControlTemplate中的VisualTransition
VisualTransition是控件模板中的重要组成部分,无论是自定义控件或者修改控件样式都会接触到VisualTransition。明明这么重要,博客园上好像都没多少关于VisualTransition的主题。
dino.c
2019/01/18
6780
[UWP]理解ControlTemplate中的VisualTransition
win10 uwp 按下等待按钮
我们需要一个值让我们知道是不是已经完成了后台,按钮可以按下,在按下时,自动让按钮IsEnable为false。
林德熙
2018/09/18
7580
win10 uwp 按下等待按钮
[UWP]做个调皮的BusyIndicator
最近突然想要个BusyIndicator。做过WPF开发的程序员对BusyIndicator应该不陌生,Extended WPF Toolkit 提供了BusyIndicator的开源实现,Silverlight Toolkit也有一个,这次想要把这个控件移植到UWP中。
dino.c
2019/01/18
9080
[UWP]做个调皮的BusyIndicator
[UWP]为番茄钟应用设计一个平平无奇的状态按钮
OnePomodoro应用里有个按钮用来控制计时器的启动/停止,本来这应该是一个包含“已启动”和“已停止”两种状态的按钮,但我以前在WPF和UWP上做过太多StateButton、ProgressButton之类的东西,已经厌倦了这种控件,所以我在OnePomodoro应用里只是简单地使用两个按钮来实现这个功能:
dino.c
2019/11/13
6970
[UWP]新控件ColorPicker
Fall Creators Update中提供了一个新得ColorPicker控件,解决了以前选择颜色只能用Combo Box的窘境。
dino.c
2019/01/18
6970
[UWP]新控件ColorPicker
[WPF自定义控件库]自定义Expander
上一篇文章介绍了使用Resizer实现Expander简单的动画效果,运行效果也还好,不过只有展开/折叠而缺少了淡入/淡出的动画(毕竟Resizer模仿Expander只是附带的功能)。这篇继续Measure的话题,自定义了一个带有动画的ExtendedExpander。
dino.c
2019/07/26
1.1K0
[WPF自定义控件库]自定义Expander
[UWP 自定义控件]了解模板化控件(5):VisualState
使用TemplatePart实现上篇文章的两个需求(Header为空时隐藏HeaderContentPresenter,鼠标没有放在控件上时HeaderContentPresent半透明),虽然功能已经实现,但这样实现的话基本上也就别想扩展了。譬如开发者做不到通过继承或修改ControlTemplate实现如下功能:
dino.c
2019/01/18
5280
[UWP 自定义控件]了解模板化控件(5):VisualState
Silverlight Telerik控件学习:RadTransitionControl
如果展示类似这种比较cool的图片轮换效果,用RadTransitionControl控件就对了,它提供的过渡效果非常cool! 原理并不复杂,可参见以前写的 Silverlight之ListBox/Style学习笔记--ListBox版的图片轮换广告. xaml部分: <UserControl xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="Telerik.Sample.Transition"
菩提树下的杨过
2018/01/23
8090
Silverlight Telerik控件学习:RadTransitionControl
[UWP]实现Picker控件
在WPF中,很多打开下拉框(Popup或Flyout)选择一个结果值的控件,除了ComboBox等少数例外,这种控件都以-Picker做名称后缀。因为要打开关闭下拉框和计算下拉框的弹出位置, 这类控件实现起来还挺麻烦的。Silverlight Toolkit中贴心地提供了一个Picker控件,可以作为这类控件的基类,省略了大量代码。
dino.c
2019/01/18
1.1K0
[UWP]实现Picker控件
SilverLight企业应用框架设计【二】框架画面
注意,这里每个顶部菜单的ICO图标不是动态的,朋友们,想让他变成动态的就自己动手吧
liulun
2022/05/09
6120
SilverLight企业应用框架设计【二】框架画面
win10 uwp 异步进度条 圆形进度条
进度条可以参见:http://edi.wang/post/2016/2/25/windows-10-uwp-modal-progress-dialog
林德熙
2018/09/18
1.6K0
win10 uwp 异步进度条
            圆形进度条
New UWP Community Toolkit - ImageEx
概述 UWP Community Toolkit  中有一个图片的扩展控件 - ImageEx,本篇我们结合代码详细讲解  ImageEx 的实现。 ImageEx 是一个图片的扩展控件,包括 Ima
Shao Meng
2018/04/28
9980
New UWP Community Toolkit - ImageEx
Silverlight button 图片切换样式
之前一直做WPF现在开始接触Slilverlight感触很多。 今天做一个Button要求 有两个图片,button默认有一个图片,鼠标over时用另一个图片, 用wpf做的时候写一个template很简单,但silverlight和wpf写起来不一样 记录一下。大概思路是两个image鼠标MouseOver的时候一个Visible一个Collapsed 写的是一个自定义控件,代码和皮肤分离,很简单的一个demo 代码下载:ImageButtonTest.rar 先写一个继承自button的imagebut
lpxxn
2018/01/31
2.1K0
win10 uwp 修改Pivot Header 颜色
参见: http://stackoverflow.com/questions/31797875/overriding-pivot-header-foreground-brushes-in-uwp-app-win-10-rtm-sdk
林德熙
2018/09/19
6580
win10 uwp 修改Pivot Header 颜色
[UWP] 模仿哔哩哔哩的一键三连
去年在云之幻大佬的 哔哩 项目里看到一键三连的 UWP 实现,觉得挺有趣的,这次参考它的代码重新实现一次,最终成果如下:
dino.c
2021/03/11
1.1K0
[UWP] 模仿哔哩哔哩的一键三连
win10 uwp 横向 AppBarButton
一般看到的 AppBarButton 都是图片在上面,文字在下面,是否可以更改让文字在和图片相同的位置?本文告诉大家如何做出横向的 AppBarButton 把图标和文本放在一起。
林德熙
2018/09/18
4450
win10 uwp 横向 AppBarButton
win10 uwp 使用资源在后台创建控件
本文告诉大家如何使用资源在后台创建控件,本文使用按钮做例子,包括如何绑定资源,找到资源。
林德熙
2018/09/19
6560
win10 uwp 使用资源在后台创建控件
[WPF自定义控件库]以Button为例谈谈如何模仿Aero2主题
除了以外观为卖点的控件库,WPF的控件库都默认使用“素颜”的外观,然后再提供一些主题包。这样做的最大好处是可以和原生控件或其它控件库兼容,而且对于大部分人来说模仿原生的主题也比自己设计一套好看的UI容易得多。
dino.c
2019/05/29
1.2K0
相关推荐
[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验