Win10 UWP开发中的重复性静态UI绘制小技巧 2

小技巧1 地址:http://www.cnblogs.com/ms-uap/p/4641419.html

介绍

我们在上一篇博文中展示了通过Shape.Stroke族属性实现静态重复性UI绘制,使得UWP界面的实现变得稍微灵活一些了。

但这一技巧还是有不少局限的,毕竟折腾StrokeDashArray属性看上去并不是那么直观和适用(还存在用扇形欺骗观众这样的“问题”啦)。

这一篇博文我们将为大家介绍一种更为适用,同时也更为灵活和强大的重复性UI绘制技巧。

ItemsControl.ItemsSource和

ItemsControl.ItemTemplate组合技

ItemsControl是一个很常见的控件,虽然它经常是以ListView、ListBox等衍生类的形式出现,想必大家也是经常使用它们。

而ItemsControl本身,则提供了最基本的“作为对象集合”的功能。

而其中ItemsControl.ItemsSource和ItemsControl.ItemTemplate两个属性最为重要。前者将通过指定策略预处理的数据赋予控件,后者将源数据映射为UI元素。

灵活运用它们,就能方便的做出精准而又快速的设计。

比如:

<Grid>
    <Grid.Resources>
        <design:AngleSource x:Key="source"/>
    </Grid.Resources>

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center"
          Width="200" Height="200">
        <ItemsControl ItemsSource="{Binding Source={StaticResource source}, Path=Items}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Control.VerticalAlignment" Value="Stretch"/>
                    <Setter Property="Control.HorizontalAlignment" Value="Center"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid RenderTransformOrigin="0.5,0.5">
                        <Line Stroke="Black" StrokeThickness="10" X1="5" X2="5" Y2="20" />

                        <Grid.RenderTransform>
                            <RotateTransform Angle="{Binding}"/>
                        </Grid.RenderTransform>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Grid>

让我们把目光放得“短浅”一点:),此处是不是完美解决了欺骗观众的问题?

一个小小的问题的解决,有时能带出新的解决方案和模式。那么让我们看看这段XAML有什么作用?

首先,AngleSource是这样一个类:

public class AngleSource
{
    public IEnumerable<double> Items
    {
        get
        {
            return Enumerable.Range(0, 12).Select(d => d * 30.0);
        }
    }
}

它的作用就是提供一个数列,里面的数代表了我们要显示的线段相对图形中心的旋转角度。

这个AngleSource类,以静态资源的形式,将其含有的数列暴露给ItemsControl的ItemsSource属性:

ItemsSource="{Binding Source={StaticResource source}, Path=Items}"

然后我们通过自定义ItemTemplate,将简单的double数值具现为旋转的图形!

通过这种方式,我们可以使用简单的代码,来完成其最擅长的事,即按某种策略生成源数据。

PS:如果只有简单的数个元素,不使用ItemsSource+Binding也是可以的,只要像这样:

<ItemsControl>
    <x:Double>30</x:Double>
    <x:Double>60</x:Double>
    <x:Double>90</x:Double>
</ItemsControl>

<ItemsControl>
    <local:FooItem Bar="123" Baz="456"/>
    <local:FooItem Bar="789" Baz="233"/>
</ItemsControl>

我们还使用ItemsControl.ItemsPanel、ItemsControl.ItemContainerStyle两个属性配合,让每个线段能以表盘的中心为参考点进行旋转:

1)ItemContainerStyle是对Item的区域进行外围定制(Item本身交给ItemTemplate了)。

2)ItemsPanel的作用是定义元素在控件中的布局形式,默认的是StackPanel,也就是常见的ListBox和ListView的形式。

常见的还有:

<Grid/>   <!-- 可以自动对齐 -->
<Canvas/> <!-- 一般为绝对定位,容易调整图层,并可以超出范围 -->

整个ItemsControl的层级大致如下:

同理,更多的变化呼之欲出:

这里我们简单地做两种扩展,更多的组合期待大家的灵活运用~

1. 带时间的表盘

<Grid>
    <Grid.Resources>
        <design:AngleSource x:Key="source"/>
        <design:AngleClockConverter x:Key="toClock"/>
    </Grid.Resources>

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center"
          Width="200" Height="200">
        <ItemsControl ItemsSource="{Binding Source={StaticResource source}, Path=Items}"
                      RenderTransformOrigin="0.5,0.5">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Control.VerticalAlignment" Value="Stretch"/>
                    <Setter Property="Control.HorizontalAlignment" Value="Center"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid RenderTransformOrigin="0.5,0.5" Width="50">
                        <TextBlock Text="{Binding Converter={StaticResource toClock}}"
                                   HorizontalAlignment="Center"/>
                        <Line Stroke="Black" StrokeThickness="10"
                              X1="5" X2="5" Y1="20" Y2="40"
                              HorizontalAlignment="Center"/>
                        <Grid.RenderTransform>
                            <RotateTransform Angle="{Binding}"/>
                        </Grid.RenderTransform>
                   </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid></Grid>

这段XAML不仅按角度画出了旋转的线段,还在此通过一个converter对源数据进行了一次映射。是不是有点linq select的感觉?

2. 斐波那契数列

<Grid>
    <Grid.Resources>
        <design:FibonacciSource x:Key="fibonacci"/>
    </Grid.Resources>
    <ItemsControl Margin="20"
                  ItemsSource="{Binding Source={StaticResource fibonacci}, Path=Items}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Canvas>
                    <Line Y2="30" Stroke="Black"/>
                    <!-- 由于我们的Left定位实际只用于上面的Line -->
                    <!-- 那我们怎让下面的数值显示能居中于Line呢? -->
                    <!-- 因为Canvas是允许其内容的渲染超出范围的,我们可以以此先用Grid开辟一个足够大的空间 -->
                    <!-- 再在其中将TextBlock居中 -->
                    <Grid Width="50" Canvas.Left="-25" Canvas.Top="40">
                        <TextBlock HorizontalAlignment="Center" Text="{Binding}"/>
                    </Grid>
                </Canvas>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

这段XAML也是很有趣,其中的ItemsSource仅仅是提供了一个IEnumerable<int>,也就是斐波那契数列,

而我们控制Canvas.Left画出了一系列标注线,它们距左端的位移分别是斐波那契数列的值!

或许在一些数理教学的App里能用得上呢……

另外

Source类同样可以暴露出使用形如FoobarItem的IEnumerable<T>,就可以在FoobarItem中设置更多更丰富的属性,

然后在ItemsControl.ItemTemplate(DataTemplate)进行Binding,辅以Style和Converter,实现更加丰富的效果。

这样做有什么好处?

这两篇博文为大家介绍了两种绘制重复性UI的办法,那我们掌握这些办法有什么意义,或者说我们能获得什么好处呢?

解耦。

将这些与程序逻辑完全无关的UI设定,完全地与功能逻辑剥离开。即使需要写一些代码,也和功能逻辑完全没有关联。

让code behind清爽,更加专注于功能的实现,而UI的变换仍旧是动态的。

精确。

由于使用XAML和原始数据生成UI,所以UI元素的属性和位移、旋转等变换是完全精准的,免去手工校准之虞。

并且配合CacheMode和ViewBox,使得UI在适配和渲染时表现清晰不失真,兼顾性能。

同时也提供了新的UI元素控制方式。

比如例子中的圆形进度条的实现。我们可以在后台代码中更新StrokeDashArray来展示进度。

又比如我们设定好了ItemsControl的数据展示策略,只需要再设定数据源,就能轻易地将其展示。

希望这两篇博客能够抛砖引玉,唤来更多创意和技巧,为大家在UWP中的开发提供方便!;)

时间: 2024-08-29 07:50:49

Win10 UWP开发中的重复性静态UI绘制小技巧 2的相关文章

UWP开发中的重复性静态UI绘制小技巧 1

介绍 在UWP界面实现的过程中,有时会遇到一些重复性的.静态的界面设计.比如:画许多等距的线条,画一圈时钟型的刻度线,同特别的策略排布元素,等等. 读者可能觉得这些需求十分简单,马上就想到了通过for循环之类来实现.只需要在Loaded事件里添上这些元素就好了. 但这样可能存在一些问题——如果这些UI元素只是静态的,是装饰性的——虽然code-behind不用白不用,但为了这些纯静态元素将代码逻辑变得臃肿似乎略有不妥. 我们将就这些问题为读者们介绍一些重复性的静态界面绘制小技巧. Shape.S

vue vuex开发中遇到的问题及解决小技巧

1.在vue的开发中,如果使用了vuex,数据的组装,修改时在mutations中,页面是建议修改变量值的,如果强制修改,控制台就会出现错误.如下: 这种错误虽然不会影响结果,但是是vuex不提倡的方式,因此,如果想要使其不出现这种错误,可以切断vuex变量与页面变量直接的关联,最简单的方式就是: let a = JSON.parse(JSON.stringify(b)); 当然还有一种正规的方式就是在mutations中修改变量值,也就是写一个mutations方法即可 原文地址:https:

Win10 UWP开发系列——开源控件库:UWPCommunityToolkit

原文:Win10 UWP开发系列--开源控件库:UWPCommunityToolkit 在开发应用的过程中,不可避免的会使用第三方类库.之前用过一个WinRTXamlToolkit.UWP,现在微软官方发布了一个新的开源控件库—— UWPCommunityToolkit 项目代码托管在Github上:https://github.com/Microsoft/UWPCommunityToolkit 包括以下几个类库: 都可以很方便的从Nuget上安装. NuGet Package Name des

Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneGap.ionic.AngularJS这些框架或库的关系,我个人理解是这样,PhoneGap是一个商业项目,用来实现HTML5式的跨平台开发,后来Adobe公司将其中的核心代码开源,就是Cordova,Cordova只负责实现JavaScript调用原生代码的功能,是一个壳,而壳里具体用什么样式,在H

Win10 UWP开发系列:解决Win10不同版本的Style差异导致的兼容性问题

原文:Win10 UWP开发系列:解决Win10不同版本的Style差异导致的兼容性问题 最近在开发一个项目时,遇到了一个奇怪的问题,项目依赖的最低版本是10586,目标版本是14393,开发完毕发布到商店后,很多用户报无法正常加载页面.经查,有问题的都是Win10 10586版本. 我上篇博客中写到的自定义的AppBar控件,也存在这个问题,10586会报错. 为此特意下载了10586的SDK调试.错误显示,一个样式找不到,名为ListViewItemBackground.因为开发的时候是基于

Win10/UWP开发—使用Cortana语音与App后台Service交互

上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比调用前台的App,调用后台任务有个有点就是App不用被启动即可为用户提供服务. 要想使用Cortana调用App后台任务,首先我们需要定义VCD文件,我们依旧使用上篇中的代码,让它支持Cortana调用后台任务. 创建后台任务 新增一个[Windows运行时组件]项目,暂时起名叫做:XiaoMiBa

Windows10(uwp)开发中的侧滑

还是在持续的开发一款Windows10的应用中,除了上篇博客讲讲我在Windows10(uwp)开发中遇到的一些坑,其实还有很多不完善的地方,比如(UIElement.Foreground).(GradientBrush.GradientStops)[1].(GradientStop.Offset)这种设置无法生效,还有RelativePanel内的元素不能自动的适应大小,要去手动控制宽高度,以及窗口在靠边的时候一些尺寸上的错误等等.虽然是WPF技术之后的延续,但是很多地方还是要小心仔细的处理,

Win10 UWP 开发系列:使用SQLite

在App开发过程中,肯定需要有一些数据要存储在本地,简单的配置可以序列化后存成文件,比如LocalSettings的方式,或保存在独立存储中.但如果数据多的话,还是需要本地数据库的支持.在UWP开发中,可以使用SQLite.本篇文章说一下如何在UWP中使用SQLite.因为SQLite是跨平台的,版本众多,我刚开始用的时候不知道要装哪个,什么WP8的.WP8.1的.Win RT的……简直摸不着头脑.希望这篇文章能让大家少走点弯路. 其实这篇文章写到一半就看到已经有大神写了这个:http://ww

Win10/UWP开发-Ink墨迹书写

在UWP开发中,微软提供了一个新型的InkCanvas控件用来让用户能书写墨迹,在新版的Edga浏览器中微软自己也用到了该控件使用户很方便的可以在web上做笔记. InkCanvas控件使用很简单,从工具箱里拖出一个InkCanvas控件即可,InkCanvas有个属性叫InkPresenter,通过它我们可以多样化的设置我们的画笔属性,InkPresenter里面有几个重要的属性: 1 // 获取或设置输入数据用于从中提取 InkStroke 的输入设备类型. 2 3 public CoreI