WPF MVVM如何在ViewModel直接操作控件对象

早些年在WPF中使用COM组件时,需要在ViewModel中操作COM组件中的控件对象,但是这个控件对象又不支持绑定,

后面的解决办法是在窗口加载时,将控件对象以参数传递到Loaded事件的处理命令中,然后将这个对象记录下来,后面就可以直接操作这个控件了。

今天同事在使用WebView2的时候,又遇到这个问题,写个文章分享一下,给后续需要的小伙伴提供点参考。

我们创建一个WPF的项目,然后在界面上放置一个WMP控件(Windows Media Player)。

MainWindow.xaml

复制代码
 1 <Window x:Class="GetControlInViewModel.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:wmp="clr-namespace:AxWMPLib;assembly=AxInterop.WMPLib"
 7         xmlns:local="clr-namespace:GetControlInViewModel"
 8         mc:Ignorable="d"
 9         Title="MainWindow" Height="450" Width="800">
10     <Grid>
11         <WindowsFormsHost>
12             <wmp:AxWindowsMediaPlayer x:Name="WMPPlayer"></wmp:AxWindowsMediaPlayer>
13         </WindowsFormsHost>
14     </Grid>
15 </Window>

如果我们想在ViewModel中操作这个WMP对象,可以在Loaded事件中添加如下处理

这里我使用了废弃的包MvvmLight来做演示,因为比较简单方便。

复制代码
1  <i:Interaction.Triggers>
2      <i:EventTrigger EventName="Loaded">
3          <i:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=WMPPlayer}"></i:InvokeCommandAction>
4      </i:EventTrigger>
5  </i:Interaction.Triggers>

ViewModel

复制代码
 1 public class MainViewModel : ViewModelBase
 2 {
 3     private AxWMPLib.AxWindowsMediaPlayer mediaPlayer;
 4 
 5     public RelayCommand<AxWMPLib.AxWindowsMediaPlayer> OnLoadedCommand { get; private set; }
 6     
 7     public MainViewModel()
 8     {
 9         OnLoadedCommand = new RelayCommand<AxWMPLib.AxWindowsMediaPlayer>(OnLoaded);
10     }
11 
12     private void OnLoaded(AxWMPLib.AxWindowsMediaPlayer axWindowsMediaPlayer)
13     {
14         this.mediaPlayer = axWindowsMediaPlayer;
15     }
16 }

然后将ViewModel绑定到MainWindow上,运行时就可以获取到WMP对象

有时我们会遇到控件未初始化,在Loaded事件中无法获取到控件对象,类似下面这样

比如在使用Prism进行区域导航的时候,就可能会出现这个问题。

此时我们可以将整个窗口/用户控件(UserControl)传过来,然后延时一秒,或者延时加循环几次,就可以获取到控件对象

复制代码
1  private async void OnLoaded(Window window)
2  {
3      await Task.Delay(1000);
4      var webViewElement = window.FindName("WebView");
5      if (webViewElement != null)
6          this.webView = webViewElement as WebView2;
7  }

示例代码

相关推荐
小白21 小时前
WPF自定义Dialog模板,内容用不同的Page填充
wpf
Crazy Struggle1 天前
C# + WPF 音频播放器 界面优雅,体验良好
c#·wpf·音频播放器·本地播放器
James.TCG2 天前
WPF动画
wpf
He BianGu2 天前
笔记:简要介绍WPF中FormattedText是什么,主要有什么功能
笔记·c#·wpf
脚步的影子2 天前
.NET 6.0 + WPF 使用 Prism 框架实现导航
.net·wpf
jyl_sh3 天前
Ribbon (WPF)
ribbon·wpf·client·桌面程序开发·c/s客户端
wo63704313 天前
[Visual Stuidio 2022使用技巧]2.配置及常用快捷键
c#·.net·wpf
小黄人软件3 天前
wpf 字符串 与 变量名或函数名 相互转化:反射
wpf
界面开发小八哥3 天前
DevExpress WPF中文教程:如何解决排序、过滤遇到的常见问题?(二)
.net·wpf·界面控件·devexpress·ui开发
Vae_Mars3 天前
WPF中图片的宫格显示
wpf