zoukankan      html  css  js  c++  java
  • WPF中使用DynamicResource实现换肤

    这篇将介绍使用DynamicResource实现动态的界面切换功能。熟悉WPF的园友应该已经猜到了实现方式,简而言之就是动态替换DataTemplate,ControlTemplate,Style等等UI相关的属性。

    那么使用DynamicResource能让UI动态到什么程度呢?可以说,心有多大,就可以做多大,只要你想得到,就可以做出来。

    下面以展示层次数据结构为例,实现了运行时切换数据显示界面结构的功能。先来看一下要显示的数据,是一个XML文件。

    <earth>
      <country name="US">
        <family name="Bill's">
          <member name="Bill"/>
          <member name="Mark"/>
        </family>
        <family name="Hugo's">
          <member name="Hugo"/>
          <member name="Sherry"/>
        </family>
        <family name="Li's">
          <member name="Li"/>
          <member name="Jay"/>
        </family>
      </country>
      <country name="China">
        <family name="陆家">
          <member name="嘴"/>
          <member name="脸"/>
        </family>
        <family name="徐家">
          <member name="汇"/>
          <member name="仁"/>
        </family>
        <family name="黄浦">
          <member name="江"/>
          <member name="边"/>
        </family>
      </country>
    </earth>

    我们要用三种方式来展示这个数据,一种是最常见的TreeView,还可以用一组并列的ListBox,还有不太常见的嵌套式ItemsControl。如下图所示。

    图1. TreeView

    图2. ListView

    图3. GroupView

    要实现这些效果,可以使用DataTemplate。把界面中会变的部分独立出来,有人说这个界面除了上面的菜单不变,整个都在变啊。没错,那就把整个主体部分独立出来,放到DataTemplate里。而Window里就只有一个菜单和一个占位符了。如下所示。

    <Window x:Class="Skinning.DemoWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="View Demo" Height="300" Width="300">
        <DockPanel DataContext="{Binding Source={StaticResource XMLDataDataSource}}">
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="List View" Click="OnListViewClick"/>
                <MenuItem Header="Group View" Click="OnGroupViewClick"/>
                <MenuItem Header="Tree View" Click="OnTreeViewClick"/>
            </Menu>
            <ContentPresenter Content="{Binding}" ContentTemplate="{DynamicResource EarthDataTemplate}"/>
        </DockPanel>
    </Window>

    然后就是定义上面引用到的EarthDataTemplate。以ListView的DataTemplate为例,如下所示。

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <DataTemplate x:Key="NameTemplate">
            <TextBlock Text="{Binding XPath=@name}"/>
        </DataTemplate>
        <DataTemplate x:Key="EarthDataTemplate">
            <UniformGrid Rows="1" DataContext="{Binding XPath=earth/country}">
                <ListBox ItemsSource="{Binding Mode=Default}" x:Name="countryList" ItemTemplate="{StaticResource NameTemplate}"/>
                <ListBox DataContext="{Binding SelectedItem, ElementName=countryList}"
                         ItemsSource="{Binding Mode=OneWay, XPath=family}"
                         x:Name="familyList" ItemTemplate="{StaticResource NameTemplate}"/>
                <ListBox DataContext="{Binding SelectedItem, ElementName=familyList}"
                         ItemsSource="{Binding Mode=OneWay, XPath=member}"
                         ItemTemplate="{StaticResource NameTemplate}"/>
            </UniformGrid>
        </DataTemplate>
    </ResourceDictionary>

    其它的DataTemplate就不一一例出了,完整的程序可以从这里下载。

    虽然这个例子中只是展示了界面结构上的变化,只使用了DataTemplate,其它的小Case的形式的界面也完全不在话下。比如配色、控件样式、控件位置,乃至所谓的换肤,可以分解为这些技巧的组合。当你把DynamicResource、Style、TemplateSelector、Converter、MarkupExtension等各种WPF技术都用上的时候就会发现WPF可以提供很强大的界面生成功能。

    再来介绍一下这种方式的缺点。

    为什么微软的文档和WPF的相关书籍中都没有介绍这种方法呢?就像上一篇关于语言支持里列举的现有方案一样,都是要Build进DLL中呢? 我想其中一个原因就是安全上的考虑。把XAML文件这样赤祼 祼地放在外面,对于了解WPF的人来说,完全可以利用这个文件“执行任意代码”。这个很眼熟吧,常常出现在微软的各个安全补丁的描述中。而且一般会是严重的漏洞。

    这个问题虽然严重,但也是基本可以解决的。像Web中各种Editor一样,可以对XAML里的内容,过滤一下,替换一下,限制一下等等。如果还不放心,可以把自己定义XML格式来定义界面,然后在内部用XSLT转成XAML再加载。对自定义的XML加限制会更容易些。

    这篇内容比较简单,不过是为了下篇主要内容打个基础。下篇将要展示一个自定义的Window的Style,把WPF的WinForm式的边框去掉。

  • 相关阅读:
    最大子数组求和并进行条件组合覆盖测试
    Ubuntu 16.04 c++ Google框架单元测试
    The directory '/home/stone/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If execu
    Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/test -w /var/cache/app-info -a -e /usr/bin/appstreamcli; then appstreamcli refresh > /dev/null; fi'
    个人博客作业三:微软小娜APP的案例分析
    补交 作业一
    补交 作业二:个人博客作业内容:需求分析
    嵌入式软件设计第12次实验报告
    嵌入式软件设计第11次实验报告
    嵌入式软件设计第10次实验报告
  • 原文地址:https://www.cnblogs.com/lsgsanxiao/p/5970001.html
Copyright © 2011-2022 走看看