WPF从本地文件加载界面
在前面的文章中,我介绍过一种报告模板的实现思路。就是用的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 }
运行效果如下:
示例代码