在前面的文章中,我介绍过一种报告模板的实现思路。就是用的XAML本地加载。
WPF使用XAML实现报表的一种思路(支持外部加载) - zhaotianff - 博客园
在另外一篇文章中,介绍了XAML是如何被转换成对象的。
WPF中的XAML是如何转换成对象的? - zhaotianff - 博客园
在这篇文章中,简单介绍了InitializeComponent函数,它的内部如下:
在任意一个界面的构造函数下都会调用InitializeComponent 函数,也就是在InitializeComponent函数里,将XAML加载进来
1 /// <summary>
2 /// InitializeComponent
3 /// </summary>
4 [System.Diagnostics.DebuggerNonUserCodeAttribute()]
5 [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
6 public void InitializeComponent() {
7 if (_contentLoaded) {
8 return;
9 }
10 _contentLoaded = true;
11 System.Uri resourceLocater = new System.Uri("/WpfApp25;component/mainwindow.xaml", System.UriKind.Relative);
12
13 #line 1 "..\..\MainWindow.xaml"
14 System.Windows.Application.LoadComponent(this, resourceLocater);
15
16 #line default
17 #line hidden
18 }
如果我们想界面从本地文件加载,是不是也可以利用这种方法呢?
答案是不行,因为Application.LoadComponent函数仅支持相对路径的资源,也就是说必须那是嵌入的。
1 System.Windows.Application.LoadComponent(this, resourceLocater);
但是我们可以利用这种思路,只是改变一下加载方法。
我们还是使用前面的加载报告模板的那种方式。这种方式也支持三方控件。这里以HandyControl为例(HandyControl使用不作讲解)。
如果想为控件添加事件处理程序,可以通过FrameworkElement.FindName函数查找元素,并手动添加事件处理程序。
这里不作演示,本文以MVVM模式进行演示。
实现方式如下:
1、创建一个如下的UserControl
1 <UserControl x:Class="WPFDynamicLoadUI.UserControl1"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6 xmlns:local="clr-namespace:WPFDynamicLoadUI"
7 xmlns:hc="https://handyorg.github.io/handycontrol"
8 mc:Ignorable="d"
9 d:DesignHeight="450" d:DesignWidth="800">
10 <hc:TransitioningContentControl>
11 <Grid>
12 <Grid.RowDefinitions>
13 <RowDefinition/>
14 <RowDefinition Height="30"/>
15 </Grid.RowDefinitions>
16
17 <Image></Image>
18 <Button Content="确认" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1" Width="88" Height="28"></Button>
19 </Grid>
20 </hc:TransitioningContentControl>
21 </UserControl>
2、将UserControl保存到本地文件
在保存之前需要移除一些元素,例如一些资源引入,x:Class声明 等,另外还需要将元素进行绑定。
1 <UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:hc="https://handyorg.github.io/handycontrol"
6 mc:Ignorable="d"
7 d:DesignHeight="450" d:DesignWidth="800">
8 <hc:TransitioningContentControl>
9 <Grid>
10 <Grid.RowDefinitions>
11 <RowDefinition/>
12 <RowDefinition Height="30"/>
13 </Grid.RowDefinitions>
14
15 <Image Source="{Binding ImagePath}"></Image>
16 <Button Content="确认" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1" Width="88" Height="28" Command="{Binding ConfirmCommand}"></Button>
17 </Grid>
18 </hc:TransitioningContentControl>
19 </UserControl>
3、创建ViewModel
1 public class MyViewModel : ObservableObject
2 {
3 private string imagePath;
4
5 public string ImagePath
6 {
7 get => imagePath;
8 set
9 {
10 SetProperty(ref imagePath, value);
11 }
12 }
13
14 public RelayCommand ConfirmCommand { get; private set; }
15
16 public MyViewModel()
17 {
18 ConfirmCommand = new RelayCommand(Confirm);
19 }
20
21 private void Confirm()
22 {
23 Application.Current.MainWindow.Close();
24 }
25 }
4、创建从本地加载的方法
1 private void LoadUIFromLocalFile()
2 {
3 var path = Environment.CurrentDirectory + "\\CustomUI.xaml";
4
5 if (_contentLoaded)
6 {
7 return;
8 }
9
10 _contentLoaded = true;
11 System.Uri resourceLocater = new System.Uri(path, System.UriKind.Absolute);
12 System.Windows.Controls.UserControl uc = (System.Windows.Controls.UserControl)XamlReader.Parse(System.IO.File.ReadAllText(path));
13
14 MyViewModel myViewModel = new MyViewModel();
15 myViewModel.ImagePath = "https://img1.baidu.com/it/u=3587113956,547682065&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1732986000&t=718ac074cdbcbf7e38df3b6ccbd9d8b2";
16 uc.DataContext = myViewModel;
17
18 this.Content = uc;
19 }
5、移除InitializeConponent函数,变成从本地加载的函数
1 public MainWindow()
2 {
3 //InitializeComponent();
4 LoadUIFromLocalFile();
5 }
运行效果如下: