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  }

示例代码

相关推荐
LcVong4 小时前
WPF MediaPlayer获取网络视频流当前帧并展示图片完整范例
网络·wpf
bugcome_com5 小时前
WPF数据绑定入门:从传统事件到5种绑定模式
wpf
LateFrames6 小时前
我用 WPF 做了一个 “苍蝇飞舞” 的屏保
ui·wpf
wuty00716 小时前
完善基于WPF开发的标尺控件(含实例代码)
wpf·wpf标尺·支持横向竖向标尺·ruler
浩浩测试一下1 天前
洪水猛兽攻击 Ddos Dos cc Drdos floods区别
安全·web安全·网络安全·系统安全·wpf·可信计算技术·安全架构
无心水1 天前
分布式环境下定时任务与SELECT FOR UPDATE的陷阱与解决方案
分布式·后端·wpf·xxl-job·quartz·定时任务·selectforupdate
xdpcxq10291 天前
Spring AOP + Guava RateLimiter 用注解实现优雅限流
spring·wpf·guava
Aevget2 天前
界面控件DevExpress WPF v25.2新版亮点:模板工具包全新升级
wpf·界面控件·devexpress·ui开发·.net 10
czhc11400756632 天前
wpf 129
wpf
码界奇点3 天前
基于eBPF技术的高性能网络防火墙系统设计与实现
开发语言·网络·毕业设计·php·wpf·go语言·源代码管理