前言
使用wpf开发有时需要动态加载控件,直接再后台写cs代码,对于样式会很难写而且可读性会比较差,这个时候我们就需要想办法完全在xaml中定义动态加载控件的样式,虽然我们可以定义模板放在资源字典中,然后在后台获取模板在加入到界面,但这个过程还是很麻烦的而且与mvvm不兼容。更好的方法应该是使用ItemsControl,ItemsControl作为ListBox的祖先类其使用方法是基本一致的,我们可以自定义其内部的布局,以及元素模板,通过绑定数据源即可实现控件的动态加载,cs端不需要处理任何界面代码。
一、如何实现?
1、使用ItemsControl
众所周知ListBox作为列表控件是可以实现动态加载元素的,而ItemsControl就是其祖先类,我们用它就可以实现动态加载元素。或者直接ListBox也可以但是要设置的属性可能多一些,比如去除元素焦点框,元素默认边距,去除边框等等。
<ItemsControl/>
2、设置布局
我们根据使用场景设置我们需要的布局,设置ItemsControl的ItemsPanel即可。
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid></Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
3、定义控件模板
通过ItemsControl的ItemTemplate来设置我们需要需要动态加载控件的目标。而且可以通过触发器选择不同的模板,比如实现白板的控件动态加载就可以用这种方法。
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="ok" />
</DataTemplate>
</ItemsControl.ItemTemplate>
4、绑定数据源
和ListBox类似,使用ItemsSource绑定实体即可。
<ItemsControl ItemsSource="{Binding lst}" />
二、使用示例
1.动态加载形状
xaml
<Window x:Class="WpfApp2.MainWindow"
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:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ItemsControl ItemsSource="{Binding Shapes}" Height="450" Width="800">
<ItemsControl.ItemsPanel>
<!--布局-->
<ItemsPanelTemplate>
<Grid ></Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!--控件模板-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Control x:Name="ctrl" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="{Binding Margin}" Width="{Binding Width}" Height="{Binding Height}" ></Control>
<DataTemplate.Triggers>
<!--根据不同类型选择不同模板-->
<DataTrigger Binding="{Binding Type}" Value="0">
<!--矩形-->
<Setter Property="Template" TargetName="ctrl">
<Setter.Value>
<ControlTemplate >
<Rectangle Fill="RoyalBlue" RadiusX="10" RadiusY="10" Width="{Binding Width}" Height="{Binding Height}"></Rectangle>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Type}" Value="1">
<!--椭圆-->
<Setter Property="Template" TargetName="ctrl">
<Setter.Value>
<ControlTemplate >
<Ellipse Fill="GreenYellow" Width="{Binding Width}" Height="{Binding Height}"></Ellipse>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
cs
using System.Collections.Generic;
using System.Windows;
namespace WpfApp2
{
//形状实体
public class Shape
{
public int Type { set; get; }
public Thickness Margin { set; get; }
public double Width { set; get; }
public double Height { set; get; }
}
public partial class MainWindow : Window
{
public List<Shape> Shapes { set; get; } = new List<Shape>();
public MainWindow()
{
InitializeComponent();
Shapes.Add(new Shape() { Type = 0, Margin=new Thickness(10,10,0,0), Width = 200, Height = 100 });
Shapes.Add(new Shape() { Type = 0, Margin = new Thickness(300, 22 , 0, 0), Width = 280, Height = 120 });
Shapes.Add(new Shape() { Type = 1, Margin = new Thickness(33, 255, 0, 0), Width = 200, Height = 100 });
Shapes.Add(new Shape() { Type = 1, Margin = new Thickness(350, 150, 0, 0), Width = 200, Height = 200 });
DataContext = this;
}
}
}
效果预览
总结
例如:以上就是今天要讲的内容,本文仅仅介绍的方法,很好的解决了界面分离问题,尤其是在mvvm模式下,动态加载任意控件只需要通过绑定实体集合即可完成。使用的ItemsControl与ListBox用法基本一致,易于理解也方便使用。