自适应XAML布局经验总结 (三) 局部布局设计模式2

本系列对实际项目中的XAML布局场景进行总结,给出了较优化的自适应布局解决方案,希望对大家有所帮助。

下面继续介绍局部布局设计模式。

5. 工具箱模式

绘图,三维模型操作等需要工具的情况,可以使用带分类的工具箱来放置工具,以达到较好的效果。实现工具箱效果的方法是使用ItemsControl的分组功能,并修改样式和布局。

首先,在最外层放置一个横向滚动条为Auto的ScrollViewer。里面放一个ItemsControl,修改布局为UniformGrid,分两行。ItemTemplate为Button,设置合适的背景色和固定长度宽度(和字体字号相关),并设置左和上的Margin。Button的Content为TextBlock,设置文字折行和截断,并设置横向和纵向对齐方式为居中。TextBlock可设置合适的ToolTip,可使用转换器控制只在文字多的时候显示。

然后,修改ItemTemplate的GroupStyle,GroupStyle的Panel为横向的StackPanel,ContainerStyle的Template放置一个横向的StackPanel,分别放一个Rectangle做为分割竖线和一个Grid放置真正的内容。Rectangle使用转换器控制在第一个位置时不显示。Grid分为两行,第0行为Auto,第1行为*,第0行为一个放在Border里的TextBlock,设置Margin和居中对齐。第1行是ItemsPresenter,设置Margin的右和下,以和前面呼应。

最后,绑定到合适的数据源,数据源为CollectionViewSource,其Source属性为一个数据集合,数据包含ClassName和Name属性,ClassName是分类名称,Name是条目名称。在CollectionViewSource的GroupDescriptions属性中加入名为ClassName的PropertyGroupDescription。在XAML中设置合适的数据绑定即可。

<Window x:Class="BlendDemo.DP5"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BlendDemo"
        mc:Ignorable="d"
        Title="工具箱模式" Height="400" Width="500">
    <Window.Resources>
        <local:SeparatorVisibilityConverter x:Key="SeparatorVisibilityConverter"/>
        <local:LengthVisibilityConverter x:Key="LengthVisibilityConverter"/>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Border Background="LightCyan">
            <TextBlock Margin="5" Text="此处为标题" TextTrimming="WordEllipsis"/>
        </Border>
        <Grid Grid.Row="1" Background="AliceBlue"/>
        <Grid Grid.Row="2">
            <ScrollViewer HorizontalScrollBarVisibility="Auto">
                <ItemsControl ItemsSource="{Binding}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <UniformGrid Rows="2"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Button Background="AliceBlue" Width="70" MaxHeight="40" Margin="5,5,0,0">
                                <TextBlock Text="{Binding Name}" TextWrapping="Wrap" TextTrimming="WordEllipsis" HorizontalAlignment="Center" VerticalAlignment="Center"
                                      ToolTipService.Placement="Bottom" ToolTipService.InitialShowDelay="0" ToolTipService.BetweenShowDelay="0">
                                    <TextBlock.ToolTip>
                                        <ToolTip Content="{Binding Name}" Visibility="{Binding Path=Name, Converter={StaticResource LengthVisibilityConverter}, ConverterParameter=10}"/>
                                    </TextBlock.ToolTip>
                                </TextBlock>
                            </Button>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.GroupStyle>
                        <GroupStyle>
                            <GroupStyle.Panel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Horizontal" />
                                </ItemsPanelTemplate>
                            </GroupStyle.Panel>
                            <GroupStyle.ContainerStyle>
                                <Style TargetType="GroupItem">
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate>
                                                <StackPanel Orientation="Horizontal">
                                                    <Rectangle Fill="#9ca1ae" Width="2" Visibility="{Binding Path=Name, Converter={StaticResource SeparatorVisibilityConverter}}"/>
                                                    <Grid>
                                                        <Grid.RowDefinitions>
                                                            <RowDefinition Height="Auto"/>
                                                            <RowDefinition Height="*"/>
                                                        </Grid.RowDefinitions>
                                                        <Border Background="#e6e9f2">
                                                            <TextBlock Text="{Binding Name}" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                                                        </Border>
                                                        <ItemsPresenter Grid.Row="1" Margin="0,0,5,5"/>
                                                    </Grid>
                                                </StackPanel>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </GroupStyle.ContainerStyle>
                        </GroupStyle>
                    </ItemsControl.GroupStyle>
                </ItemsControl>
            </ScrollViewer>
        </Grid>
    </Grid>
</Window>
    public class SeparatorVisibilityConverter : IValueConverter
    {
        public IList Data { get; set; }

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (Data == null || Data.Count == 0)
            {
                return Visibility.Collapsed;
            }
            dynamic item = Data[0];
            return ((string)value) == item.ClassName ? Visibility.Collapsed : Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }
    }

    public class LengthVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
            {
                return Visibility.Collapsed;
            }
            return ((string)value).Length < int.Parse((string)parameter) ? Visibility.Collapsed : Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }
    }

    public class DataItem
    {
        public string ClassName { get; set; }
        public string Name { get; set; }
    }

    public partial class DP5 : Window
    {
        public DP5()
        {
            InitializeComponent();
            var cvs = new CollectionViewSource();
            cvs.Source = new List<DataItem>
            {
                new DataItem { ClassName="分类1",Name="条目1.1"},
                new DataItem { ClassName="分类1",Name="条目1.2"},
                new DataItem { ClassName="分类1",Name="条目1.3为长条目"},
                new DataItem { ClassName="分类1",Name="条目1.4"},
                new DataItem { ClassName="分类1",Name="条目1.5"},
                new DataItem { ClassName="分类2",Name="条目2.1"},
                new DataItem { ClassName="分类2",Name="条目2.2"},
                new DataItem { ClassName="分类2",Name="条目2.3"},
                new DataItem { ClassName="分类2",Name="条目2.4"},
                new DataItem { ClassName="分类2",Name="条目2.5"},
                new DataItem { ClassName="分类2",Name="条目2.6为长条目长条目长条目长条目"},
                new DataItem { ClassName="分类3",Name="条目3.1"},
                new DataItem { ClassName="分类3",Name="条目3.2"},
                new DataItem { ClassName="分类3",Name="条目3.3"},
                new DataItem { ClassName="分类3",Name="条目3.4"},
            };
            cvs.GroupDescriptions.Add(new PropertyGroupDescription("ClassName"));
            DataContext = cvs;
            ((SeparatorVisibilityConverter)FindResource("SeparatorVisibilityConverter")).Data = (IList)cvs.Source;
        }
    }

6. 选择题模式

制作选择题考试界面时,需要达到纸质选择题考试的效果。选项的排列方式分几种情况,选项文字少的时候排在一行上,文字不太多的时候分两列排,文字较多的时候按一列排。

首先,构造合适的数据结构,并加入一些示例数据。编写一个模板选择器,用于根据选项的数据情况选择合适的显示模板。全部选项的文字都小于4个字时,使用折行选项模板。全部选项的文字都小于10个字时,使用两列选项模板。其他情况使用一列选项模板。

然后,分别编写模板。折行选项模板使用ItemsControl,布局改为WrapPanel,数据模板使用StackPanel,其中放置序号,点和内容。两列选项模板使用ItemsControl,布局改为UniformGrid,列数为2,数据模板使用Grid,分为3列,前2列为Auto,放置序号和点,最后1列为*,放置显示Content的TextBlock,并设置折行。一列选项模板使用ItemsControl,不修改布局,数据模板和两列的情况相同。

最后,选择题的整体显示使用放置在ScrollViewer中的ItemsControl,不修改布局。数据模板使用StackPanel,首先放置一个Grid,分为3列,前2列为Auto,放置序号和点,最后1列为*,放置显示问题的TextBlock,并设置折行。下面放一个ContentControl,Content绑定到合适的数据,并设置ContentTemplateSelector为前文所述的模板选择器。

<Window x:Class="BlendDemo.DP6"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BlendDemo"
        mc:Ignorable="d"
        Title="选择题模式" Height="400" Width="650">
    <Window.Resources>
        <DataTemplate x:Key="WrapOptionTemplate">
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" Margin="0,4,70,4">
                            <TextBlock Text="{Binding Index}"/>
                            <TextBlock Text="." Margin="3,0,3,0"/>
                            <TextBlock Text="{Binding Content}" TextWrapping="Wrap"/>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </DataTemplate>
        <DataTemplate x:Key="TwoColumnOptionTemplate">
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="0,4,0,4">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding Index}"/>
                            <TextBlock Grid.Column="1" Text="." Margin="3,0,3,0"/>
                            <TextBlock Grid.Column="2" Text="{Binding Content}" TextWrapping="Wrap"/>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid Rows="2"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </DataTemplate>
        <DataTemplate x:Key="OneColumnOptionTemplate">
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="0,4,0,4">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding Index}"/>
                            <TextBlock Grid.Column="1" Text="." Margin="3,0,3,0"/>
                            <TextBlock Grid.Column="2" Text="{Binding Content}" TextWrapping="Wrap"/>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ScrollViewer VerticalScrollBarVisibility="Auto">
            <ItemsControl ItemsSource="{Binding}" Margin="20,20,20,3">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Margin="0,0,0,7">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Text="{Binding Index}" TextWrapping="Wrap"/>
                                <TextBlock Grid.Column="1" Text="." TextWrapping="Wrap" Margin="0,0,5,0"/>
                                <TextBlock Grid.Column="2" TextWrapping="Wrap" Text="{Binding Question}"/>
                            </Grid>
                            <ContentControl Content="{Binding OptionList}" Margin="33,10,33,10">
                                <ContentControl.ContentTemplateSelector>
                                    <local:OptionTemplateSelector/>
                                </ContentControl.ContentTemplateSelector>
                            </ContentControl>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>
</Window>
    public class OptionItem
    {
        public string Index { get; set; }

        public string Content { get; set; }

    }

    public class ObjectiveTestItem
    {
        public int Index { get; set; }

        public string Question { get; set; }

        public List<OptionItem> OptionList { get; set; }

    }

    public class OptionTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var element = container as FrameworkElement;
            if (element == null) return null;
            var optionAnswerItems = item as List<OptionItem>;
            if (optionAnswerItems == null) return null;
            if (optionAnswerItems.All(i => i.Content.Length <= 4))
            {
                return element.FindResource("WrapOptionTemplate") as DataTemplate;
            }
            if (optionAnswerItems.All(i => i.Content.Length <= 10))
            {
                return element.FindResource("TwoColumnOptionTemplate") as DataTemplate;
            }
            return element.FindResource("OneColumnOptionTemplate") as DataTemplate;
        }

    }

    public partial class DP6 : Window
    {
        public DP6()
        {
            InitializeComponent();
            var data = new List<ObjectiveTestItem>();
            var item1 = new ObjectiveTestItem
            {
                Index = 1,
                Question = "短的选项",
                OptionList = new List<OptionItem>
                {
                    new OptionItem { Index="A",Content="选项1" },
                    new OptionItem { Index="B",Content="选项2" },
                    new OptionItem { Index="C",Content="选项2" },
                    new OptionItem { Index="D",Content="选项2" }
                }
            };
            data.Add(item1);
            var item2 = new ObjectiveTestItem
            {
                Index = 1,
                Question = "中等长度的选项",
                OptionList = new List<OptionItem>
                {
                    new OptionItem { Index="A",Content="中等长度的选项1" },
                    new OptionItem { Index="B",Content="选项2" },
                    new OptionItem { Index="C",Content="选项2" },
                    new OptionItem { Index="D",Content="选项2" }
                }
            };
            data.Add(item2);
            var item3 = new ObjectiveTestItem
            {
                Index = 1,
                Question = "长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项",
                OptionList = new List<OptionItem>
                {
                    new OptionItem { Index="A",Content="长的选项长的选项长的选项长的选项长的选项长的选项长的选项1" },
                    new OptionItem { Index="B",Content="选项2" },
                    new OptionItem { Index="C",Content="选项2" },
                    new OptionItem { Index="D",Content="选项2" }
                }
            };
            data.Add(item3);
            DataContext = data;
        }
    }
时间: 2024-10-06 18:10:13

自适应XAML布局经验总结 (三) 局部布局设计模式2的相关文章

Css布局系列-经典三列布局

今天给大家介绍经典三列布局和实现原理: 通过浮动(float)进行实现,如果对float不是很清楚可以去看看我上篇介绍的: 通过绝对定位布局: 通过float加margin的负值进行组合实现.  对三种情况分析: 第一种通过浮动(float)布局,特别需要注意在定义元素结构的时候要将居中元素放到right元素的后面(container->left-right-center),不能像正常那种思维去定义结构(container ->left-center-right): *{margin: 0;p

Android 布局详解 -三表格布局(TableLayout)以及重要属性

三表格布局(TableLayout)以及重要属性             TableLayout跟TableRow 是一组搭配应用的布局,TableLayout置底,TableRow在TableLayout的上方,而Button.TextView等控件就在TableRow之上,别的,TableLayout之上也可以零丁放控件.TableLayout是一个应用错杂的布局,最简单的用法就仅仅是拖沓控件做出个界面,但实际上,会经常在代码里应用TableLayout,例如做出表格的结果.本文首要介绍Ta

使用绝对定位进行三列布局

在布局中有一种特殊的情况,当布局中分多个列,并且需要对其中的不部分列进行规定宽度,需要利用绝对定位进行布局. 用三列布局为例,我们规定左列的宽度为200,右列的宽度为300,中间列的宽度自适应,即是整个body宽度除去左右列的宽度. 具体思路:将左右列设为绝对定位,使他们紧贴在左右边.将中间列的margin左右边距设为左右列的宽度.(一般我们为了美观将边距多设10px) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//E

自适应XAML布局经验总结 (二) 局部布局设计模式1

本系列对实际项目中的XAML布局场景进行总结,给出了较优化的自适应布局解决方案,希望对大家有所帮助. 下面开始介绍局部布局设计模式. 1. 工具栏模式 适用于工具栏,标题等的布局. 此块布局区域外层使用Grid,然后分为两行或三行,标题或工具栏区域为Auto,主要内容区域为*.如果是标题,使用TextBlock,设置文字的字体和字号,还有Margin,把此行撑开.如果是工具栏,可放置一个横向的StackPanel,右对齐,其中放置多个按钮,通过设置按钮的Content,Margin和Paddin

自适应XAML布局经验总结 (一)原则和页面结构设计

XAML布局回顾 Grid和StackPanel是核心布局,尤其以Grid最为重要. Grid是网格布局,XAML的设计者有可能参考了Html里的Table设计了Grid布局,但进行了改进.Html中的Table是tr套td,要想变动行列非常麻烦.XAML中的Grid使用的是指定行列序号和跨行跨列数的方式,修改起来灵活方便. Grid里行或列的大小有三种方式,一种方式是固定大小(Double值),一种方式是由里面的内容决定(Auto),一种方式是按比例分割剩余空间(Double值加*,剩余空间由

记一道css面试题 : 三栏布局两边宽度固定,中间宽度自适应,并且布局随屏幕大小改变。

前几天面试时有道css题没做出来,回来好好学习一番后把其记录下来. 题目是这样的:左中右三栏布局,左右两栏宽度固定,左右两栏的宽度为200像素,中间栏宽度自适应.当屏幕小于600px时,3栏会分别占用一行.像这样 当屏幕大于600px时,是这样 我做出来用了css3的@media,如果不用这个,好吧,水平有限想不出来... 下面是代码: <!DOCTYPE> <html> <head> <style> body{ margin: 0 ; padding: 0

CSS 布局实例系列(三)如何实现一个左右宽度固定,中间自适应的三列布局——也聊聊双飞翼

今天聊聊一个经典的布局实例: 实现一个三列布局,其中左侧和右侧的部分宽度固定,中间部分宽度随浏览器宽度的变化而自适应变化 可能很多朋友已经笑了,这玩意儿通过双飞翼布局就能轻松实现.不过,还请容我在双飞翼之外,循序渐进地介绍一下我们可以如何实现一个三列布局. 1. 首先,使用浮动布局来实现一下 See the Pen float-three-columns by xal821792703 (@honoka) on CodePen. 左侧元素与右侧元素优先渲染,分别向左和向右浮动 中间元素在文档流的

中间固定两侧自适应三栏布局

上一种布局“中间自适应两侧固定” 用了三种方法去解决,这一种是不常见的布局格式,来看下解决方法,先看简单的解决 第一种:绝对定位 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> html,body{ height: 100%; padding:

css高度已知,左右定宽,中间自适应三栏布局

css高度已知,左右定宽,中间自适应三栏布局: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X