在使用 Prism MVVM 架构开发 WPF 应用时,我们通常遵循“数据驱动 UI”的设计原则。但有时,我们希望从数据层反向获取控件实例,比如:
✔ 在后台操作对应的 Halcon 控件
HSmartWindowControlWPF
,
✔ 动态控制某一个图像窗口的图层或内容。
本篇文章将通过一个实际例子,讲解如何优雅地实现这一反向访问过程。
之前我都通过查找视觉树的方式,如果只是有一个控件还好说,但是这次我是绑定了一个ItemList,如果再通过找视觉树的方式方式就不方便了。
你可能使用了如下结构来显示多个图像项:
<ItemsControl ItemsSource="{Binding saveInfo.Graphics, Source={x:Static md:GlobalData.Instance}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2" />
ItemsPanelTemplate>
ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding SerialNumber}" />
<local:ImageView Image="{Binding Image}" />
Grid>
DataTemplate>
ItemsControl.ItemTemplate>
ItemsControl>
每项绑定到 CameraGraphicInfo
,使用自定义控件 ImageView
显示图像。
你可能想:
Graphics
里的数据模型(CameraGraphicInfo
)对象ImageView
控件实例ViewRef
属性public class CameraGraphicInfo : BindableBase
{
public string SerialNumber { get; set; }
public HImage Image { get; set; }
// 添加这个引用属性
public ImageView ViewRef { get; set; }
}
public class ImageView : Control
{
private HSmartWindowControlWPF _hSmart;
public HSmartWindowControlWPF HSmart => _hSmart;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_hSmart = GetTemplateChild("PART_hSmart") as HSmartWindowControlWPF;
// 将当前控件注册回数据模型
if (DataContext is CameraGraphicInfo info)
info.ViewRef = this;
if (_hSmart != null && Image != null)
_hSmart.HImage = Image;
}
// Image 是 DependencyProperty(略)
}
<Style TargetType="local:ImageView">
"Template" >
"local:ImageView" >
<h:HSmartWindowControlWPF x:Name="PART_hSmart"
HKeepAspectRatio="True"
HDoubleClickToFitContent="True" />
Style>
绑定 saveInfo.Graphics
后,每个 CameraGraphicInfo
都会反向持有其 ImageView
控件引用。
现在你可以在任何后台代码中轻松访问控件:
foreach (var info in GlobalData.Instance.saveInfo.Graphics)
{
var hsmart = info.ViewRef?.HSmart;
if (hsmart != null)
{
hsmart.HClearWindow();
hsmart.HImage = new HImage("fabrik.png");
}
}
虽然可以使用如下方式查找控件:
var container = itemsControl.ItemContainerGenerator.ContainerFromItem(item);
var imageView = FindVisualChild<ImageView>(container);
但这种方式依赖视觉树,繁琐、易出错、不稳定,不推荐用于复杂项目。
方法 | 原理 | 推荐级别 |
---|---|---|
✔ 控件加载时写入模型引用 | 简洁、稳定、强类型支持 | ⭐⭐⭐⭐⭐ |
❌ 查找视觉树 | 麻烦、不稳定 | ⭐ |
维护 ViewModel 映射字典 | 分离好、但代码繁琐 | ⭐⭐⭐ |
你也可以在 ImageView
控件中暴露方法,如:
public void ClearWindow() => _hSmart?.HClearWindow();
这样只需:
info.ViewRef?.ClearWindow();
就能做到跨层调用,既方便又可控。
这个技巧打破了传统 MVVM 的单向绑定思维,但在 图像处理、相机调试等需要控件深度交互的场景中非常实用。
如果你也在使用 Halcon + WPF 的组合,不妨试试这种方式,简单高效又优雅!