[UWP开发]UI模板(一)

这篇博客介绍了如何在UWP应用中创建一个图文混排的UI模板,适用于文章展示。模板包括左侧的文字内容和右侧的图片,支持根据窗口大小自动调整布局。内容涵盖Model、ViewModel和View的定义,以及数据绑定和模板引用的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[UWP开发]UI模板(一)

总结一些以前用过的界面框架,贴出来给新手参考。
先介绍一个用于文章的图文混排,具有列表的格式。

模板1

左边为标题,文字内容。下面为一个List结构,包含标题和内容。右边为图片。

1 . Model

整体结构

public class ProductListItem
{
    public ProductListItem(string title, string content, List<TitleContent> li, PageType frameType, Uri pic)
    {
        Title = title;  //标题
        Content = content;  //文本内容
        Li = li;  //列表
        FrameType = frameType;  //页面标记,定义为enum
        Pic = pic;  //图片路径
    }

    public string Title { get; set; }
    public string Content { get; set; }
    public PageType FrameType { get; set; }
    public List<TitleContent> Li { get; set; }
    public Uri Pic { get; set; }
    public ImageSource Is
    {
        get
        {
            return new BitmapImage(Pic);
        }
    }
}

列表结构

public class TitleContent
{
    public TitleContent(string title, string content)
    {
        Title = title;
        Content = content;
    }

    public string Title { get; set; }
    public string Content { get; set; }
}

2 . ViewModel

class ProductListViewModel
{
    public List<ProductListItem> SelectedProductItems = new List<ProductListItem>();
    public List<ProductListItem> _ProductItems = null;

    public ProductListViewModel()
    {
        if (_ProductItems == null)
        {
            InitProductItems();
        }
    }

//所有的赋值操作
    public void InitProductItems()
    {
        var resourceLoader = ResourceLoader.GetForCurrentView();
        _ProductItems = new List<ProductListItem>();
        List<TitleContent> Tc = new List<TitleContent>();
        Tc.Add(new TitleContent("Universal Windows Application1", "Hello World!"));
        Tc.Add(new TitleContent("Universal Windows Application2", string.Empty));
        Tc.Add(new TitleContent("Universal Windows Application3", "Good!"));
        _ProductItems.Add(new ProductListItem("优快云 Blog", "http://blog.youkuaiyun.com/xiahn1a", Tc, PageType.ProductPage1, new Uri("ms-appx:///Assets/rocket.jpg")));
    }

//根据页面的标记,选出用于该页面的信息
    public void GetSelectedItem(PageType pt)
    {
        SelectedProductItems = _ProductItems.Where(i => i.FrameType == pt).ToList();
    }
}

3.View

xmlns:ValueConverters="using:MyApp.ValueConverters"

定义列表数据模板:

<Page.Resources>
    <ValueConverters:StringEmptyToVisibilityConverter x:Key="StringEmptyToVisibilityConverter"/>
    <DataTemplate x:Key="MainProductItemTemplate" x:DataType="local:TitleContent">
        <StackPanel>
            <Grid Margin="0,0,0,5">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="auto"></ColumnDefinition>
                    <ColumnDefinition Width="*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <SymbolIcon Grid.Column="0" Symbol="Accept" Foreground="#FF1ABC9C" />
                <TextBlock Grid.Column="1" Text="{x:Bind Title}" Margin="15,5,0,5" FontSize="16" TextWrapping="Wrap"/>
            </Grid>
            <TextBlock Text="{x:Bind Content}" FontSize="16" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" TextWrapping="Wrap" Visibility="{x:Bind Content, Converter={StaticResource StringEmptyToVisibilityConverter}}" Margin="0,0,0,5"/>
        </StackPanel>

    </DataTemplate>
</Page.Resources>

其中用到的Converter,意义在于设定部分可见性。此处定义为,如果字符串为空,则该部分不可见。这样使得模板在某部分信息缺失时也可用,不会影响排版。Converter定义如下:

namespace MyApp.ValueConverters
{
    public class StringEmptyToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (value == null)
                return Visibility.Collapsed;

            var result = (string)value;

            return result.Equals(string.Empty) ? Visibility.Collapsed : Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}

定义左侧文字整体结构:

<Grid x:Name="Grid_Main" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel Margin="0,20,0,0">
        <TextBlock x:Name="Tb_Title" Text="{Binding Title}" FontSize="20" HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Top" Foreground="#FF1ABC9C" TextWrapping="Wrap" FontWeight="Normal"/>
        <TextBlock x:Name="Tb_Content" Text="{Binding Content}" FontSize="16" Margin="10,10,10,10" VerticalAlignment="Top" TextWrapping="Wrap" Visibility="{Binding Content, Converter={StaticResource StringEmptyToVisibilityConverter}}"/>
        <ListView x:Name="Lv_Main" ItemTemplate="{StaticResource MainProductItemTemplate}" HorizontalContentAlignment="Stretch" Style="{StaticResource ListViewStyle1}" ItemContainerStyle="{StaticResource TitleItemContainerStyle}" ItemsSource="{Binding Li}" Margin="10,0,10,0"/>
    </StackPanel>
</Grid>

其中对ListView的Style进行了修改,主要目的是删减多余的动画效果。代码过长且并不关键,不贴了。

对应的后台cs文件:

public sealed partial class ProductListView : Page
{
    public ProductListView()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        DataContext = e.Parameter;
    }
}

界面定义时已进行数据绑定,此处只需DataContext = e.Parameter;赋值即可。

模板的引用方法:
在页面中定义一个Frame,后台代码中只需完成Frame跳转即可。

public sealed partial class ProductPage1 : Page
{
    private readonly ProductListViewModel _viewModel;

    public ProductPage1()
    {
        this.InitializeComponent();

        _viewModel = new ProductListViewModel();  //viewmodel
        _viewModel.GetSelectedItem(PageType.ProductPage1);  //选出用于本页使用的部分
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        MainFrame.Navigate(typeof(ProductListView), _viewModel.SelectedProductItems[0]);  //跳转页面,传递数据
    }
}

如以后需要再使用该模板创建更多的实例,则在ViewModel中赋值,对_ProductItems加入更多信息。以PageType这个标记作为引用时的区分。引用不同数据时只需改PageType这一个参数即可。


已经完成了左边文字部分的模板定义。现在把图片加入进去,并且设置,当窗口过小时,排版规则从文字图片左右排布,变为上下排布。
再定义一个View:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"></ColumnDefinition>
        <ColumnDefinition Width="1*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"></RowDefinition>
        <RowDefinition Height="1*" MinHeight="300"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid x:Name="Grid1" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Grid.RowSpan="1" Margin="5">
        <Frame x:Name="ProductFrame"></Frame>
    </Grid>
    <Grid x:Name="Grid2" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Grid.RowSpan="1" Margin="5">
        <Grid.Background>
            <ImageBrush ImageSource="{Binding Is}" Stretch="Uniform"/>
        </Grid.Background>
    </Grid>

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="{StaticResource LargeWindowSnapPoint}" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="Grid1.(Grid.Column)" Value="0"/>
                    <Setter Target="Grid1.(Grid.ColumnSpan)" Value="1"/>
                    <Setter Target="Grid1.(Grid.Row)" Value="0"/>
                    <Setter Target="Grid1.(Grid.RowSpan)" Value="2"/>
                    <Setter Target="Grid2.(Grid.Column)" Value="1"/>
                    <Setter Target="Grid2.(Grid.ColumnSpan)" Value="1"/>
                    <Setter Target="Grid2.(Grid.Row)" Value="0"/>
                    <Setter Target="Grid2.(Grid.RowSpan)" Value="2"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

代码较多,但实际上只是定义了一个触发器。当窗口大小小于某个数值的时候,将Grid1和Grid2的左右排布变为上下排布。Grid1中的Frame即为上面定义的左侧文字部分。
后台代码与定义左侧部分时基本相同,代码如下:

public sealed partial class ProductListFullView : Page
{
    public ProductListFullView()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        DataContext = e.Parameter;
        ProductFrame.Navigate(typeof(ProductListView), e.Parameter);
    }
}

对于模板的修改,减少内容可以定义Visibility,利用Converter对于绑定参数内容,判断是否为空,决定可见性。
可根据实际情况进行修改,此类模板的定义基本大同小异。


代码通过Visual Studio 2017测试。
转载请注明出处。
请不要私信索要代码,代码都是从完整的工程中节选并简化的,写完这个文档以后我也没有留存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值