从ViewModel操纵视图
本文关键字:视图 操纵 ViewModel | 更新日期: 2023-09-27 18:17:20
早上好,提前感谢您的回答。
我的视图实现了一个pan &缩放库:用于缩放和平移的WPF自定义控件
在视图中,有一个控件可以根据鼠标双击缩放到一个点:
private void zoomAndPanControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if ((Keyboard.Modifiers & ModifierKeys.Shift) == 0)
{
Point doubleClickPoint = e.GetPosition(content);
zoomAndPanControl.AnimatedSnapTo(doubleClickPoint);
}
}
我想强制"zoomAndPanControl.AnimatedSnapTo(doubleClickPoint);"到一个特定的点基于ViewModel数据的几何点,我画,当我拉它。视图会平移到新几何体的x,y坐标。几何图形/点已经绑定到视图。
作为补充说明,提取几何点的数据发生在DispatchTimer中。当读取新的几何线时,我希望视图平移。
是否有一个简单的方法来访问这个控件从ViewModel,当我得到数据?可能模拟鼠标事件与自定义点?我不知道该怎么做才好。
要通过绑定来控制View,你的控件需要绑定到一些东西。
- 为你的自定义控件添加一个接受'Point'类型的依赖属性
- 绑定INotifyPropertyChanged属性从你的视图模型实现到DP -注意,一个ValueConverter可以添加在这里,如果你想避免使用'Point'类在你的VM。
- 在您的DP定义中,调整setter以触发AnimatedSnapTo(…)方法
希望对你有帮助。
我通常处理这类场景的方式是在ViewModel上定义一个委托,在View中设置它,并在需要时调用它:
在ViewModel中定义一个方法,该方法接受一个Action<Point>
和一个Point
对象作为当前鼠标位置:
public void ExecuteAnimatedSnapTo(Action<Point> animatedSnapToAction, Point pointerPosition)
{
if (animatedSnapToAction != null && pointerPosition != null)
{
// Create a new point based on the one passed in and data in ViewModel
Point newPoint =
new Point(pointerPosition.X + viewModelData.X, pointerPosition.Y + viewModelData.Y);
// Invoke the delegate using the new point
animatedSnapToAction(newPoint);
}
}
然后在视图后面的代码中,执行这个方法:
private void zoomAndPanControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if ((Keyboard.Modifiers & ModifierKeys.Shift) == 0)
{
Point doubleClickPoint = e.GetPosition(content);
var viewModel = (MyViewModel)this.DataContext;
viewModel.ExecuteAnimatedSnapTo(zoomAndPanControl.AnimatedSnapTo, doubleClickPoint);
}
}
使用这种方法,您仍然可以保持View与ViewModel的隔离。当[单元]测试VM时,当传递到方法中时,委托和点可能是空的。if
块然后阻止"UI"逻辑被测试。
你需要注意的一件事是,如果ViewModel数据是在不同的线程上计算的,你必须在UI调度程序上执行委托。
编辑
我的印象是ViewModel拥有在MouseDoubleClick
被触发时调用委托所需的所有数据。如果不是这样,更好的解决方案是将Action
作为VM的属性公开,并在需要时调用它:
public Action<Point> AnimatedSnapToAction { get; set; }
在View上创建VM实例时,也要设置该属性:
public MyView()
{
InitializeComponent();
MyViewModel viewModel = new MyViewModel();
viewModel.AnimatedSnapToAction = zoomAndPanControl.AnimatedSnapTo;
this.DataContext = viewModel;
}
现在您可以随时在VM上执行委托。例如,如果需要在DispatcherTimer
的滴答声中调用它,它看起来像这样:
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
// Calculate geometry data
if(AnimatedToSnapAction != null)
{
AnimatedSnapToAction(pointCalculatedUsingGeometryData);
}
}
视图模型应该公开视图需要显示和交互的数据和行为,它永远不应该有对视图本身的引用。
View隐式或显式地引用了ViewModel。通过这个引用,你可以调用方法,绑定数据,连接事件等…
为了在这种情况下保持简单,您可能希望在用户双击控件时在ViewModel上执行命令,然后可以在命令执行中修改ViewModel公开的任何公共属性。然后可以使用这些属性来确定要缩放到的点。