我正在使用需要窗口句柄的外部库。我的应用程序架构是MVVM,但外部库并不完全适合这种架构。我已经确定视图模型是调用需要窗口句柄的初始化函数的最合适的位置。如何从我的视图到我的视图模型获取窗口句柄?
答案 0 :(得分:4)
通常,您的视图模型不应该知道视图的实现细节(例如它的HWND)。但是,正如您的问题所示,您使用的外部库需要您初始化它,并且您只能在一个地方执行此操作。假设您的视图模型最适合它(它甚至可能属于模型),您可以执行以下操作。
只要所有部分都可用,此实现就会为您的视图模型提供窗口句柄。请注意,您在your previous question中提供的视图模型实现需要视图模型的构造函数中的HWND。您将不得不更改视图模型,以便通过显式调用的方法或属性进行初始化。在下面的代码中,我假设您的视图模型中有一个名为OnWindowHandleAvailable
的方法。您当然可以调用该方法Initialize
,或者您可以在您明确设置的视图模型上放置Handle
属性。
public partial class View
{
public View()
{
InitializeComponent();
this.Loaded += View_Loaded;
this.DataContextChanged += View_DataContextChanged;
}
private void View_Loaded(object sender, RoutedEventArgs e)
{
GiveWindowHandleToViewModel();
}
private void View_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
GiveWindowHandleToViewModel();
}
private void GiveWindowHandleToViewModel()
{
// get view model
var viewModel = this.DataContext as ViewModel;
if (viewModel == null)
return;
// get window handle
var windowHandle = this.GetWindowHandle();
if (windowHandle == IntPtr.Zero)
return;
// signal view model
viewModel.OnWindowHandleAvailable(windowHandle);
}
private IntPtr GetWindowHandle()
{
// get window
var window = Window.GetWindow(this);
if (window == null)
return IntPtr.Zero;
// get window handle
return new WindowInteropHelper(window).Handle;
}
}
答案 1 :(得分:1)
这也可以在没有 View 使用命令访问 ViewModel 的情况下实现。
在 View.xaml.cs 中
private void View_Loaded(object sender, RoutedEventArgs e)
{
// Get the Window
var win = WinTools.FindParentWindow(this);
if (win != null) // stops designer errors
{
var winHan = new WindowInteropHelper(win).Handle;
// Execute the command with Window handle as parameter
WinInfo?.Execute(winHan);
}
}
// Command Property
public ICommand WinInfo
{
get => (ICommand)GetValue(WinInfoProperty);
set => SetValue(WinInfoProperty, value);
}
public static readonly DependencyProperty WinInfoProperty =
DependencyProperty.RegisterAttached("WinInfo",
typeof(ICommand),
typeof(View));
在 xaml 中
<View WinInfo="{Binding WinInfoCmd}" />
最后在 ViewModel.cs
private IntPtr _winHandle;
// setup to receive command
private RelayCommand _winInfoCmd;
public ICommand WinInfoCmd { get { return _winInfoCmd ??= new RelayCommand(o => SetWin((IntPtr)o), o => true); } }
private void SetWin(IntPtr han)
{
_winHandle = han;
}