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  }

示例代码

相关推荐
Chris _data11 天前
WPF 学习第三天 — Modbus RTU 串口通信
hadoop·学习·wpf
Peter(阿斯拉)11 天前
[Android]_[中级]_[如何创建MVVM架构原型]
android·java·架构·mvvm·viewmodel
布吉岛的石头12 天前
Java 程序员第 43 阶段05:微服务整合大模型,跨服务调用架构设计实战,Seata分布式事务实战
wpf
步步为营DotNet12 天前
基于.NET Aspire 实现云原生应用的高效监控与可观测性
云原生·.net·wpf
芒鸽12 天前
HarmonyOS 分布式开发实战:设备协同、数据共享与跨设备迁移
分布式·wpf·harmonyos
Volunteer Technology12 天前
Flink状态管理与容错(二)
大数据·flink·wpf
happyprince13 天前
07_verl-Trainer模块详解
人工智能·架构·wpf·强化学习
bugcome_com13 天前
WPF + Prism 技术指南与实战项目(二、模板搭建)
wpf
小满Autumn14 天前
log4net 日志框架 — 从配置到实战速查手册
笔记·c#·.net·wpf·上位机·log4net
政沅同学14 天前
基于 C# WPF + HALCON 的工业视觉算法工具框架(开源)
开发语言·c#·wpf