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  }

示例代码

相关推荐
月落.13 小时前
WPF的<ContentControl>控件
wpf
就是有点傻13 小时前
WPF中的依赖属性
开发语言·wpf
wangnaisheng13 小时前
【WPF】把一个Window放在左上角/右上角顶格显示
wpf
WineMonk13 小时前
.NET WPF CommunityToolkit.Mvvm框架
.net·wpf·mvvm
月落.13 小时前
WPF中的INotifyPropertyChanged接口
wpf
界面开发小八哥13 小时前
界面控件DevExpress WPF中文教程:Data Grid——卡片视图设置
.net·wpf·界面控件·devexpress·ui开发
平凡シンプル13 小时前
WPF 打包
wpf
VickyJames14 小时前
基于XAML框架和跨平台项目架构设计的深入技术分析
wpf·开源分享·unoplatform·winui3·项目架构
冷眼Σ(-᷅_-᷄๑)17 小时前
WPF缩放动画和平移动画叠加后会发生什么?
wpf·动画
△曉風殘月〆19 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm