从ViewModel处理视图

时间:2014-08-08 15:07:54

标签: c# wpf mvvm viewmodel

早上好,提前谢谢你回答。

我的观点实现了一个平底锅和一个缩放库:A WPF Custom Control for Zooming and Panning

在视图中,有一个控件可以根据鼠标双击缩放到一个点:

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 coords的点。几何/点已绑定到视图。

作为补充说明,在DispatchTimer中提取几何点的数据。随着新几何坐标的读取,我希望看到pan& amp;请遵循这些协调。

当我获取数据时,是否有一种从ViewModel访问此控件的简单方法?可能使用自定义点模拟鼠标事件?我不确定最好的方法。

3 个答案:

答案 0 :(得分:2)

要控制您通过绑定查看,您的控件需要绑定到的内容。

  1. 将依赖项属性添加到接受“点”类型的自定义控件。
  2. 将从视图模型实现的INotifyPropertyChanged属性绑定到该DP - 注意,如果您想避免在VM中使用“Point”类,可以在此处添加ValueConverter。
  3. 在DP的定义中,调整setter以触发AnimatedSnapTo(...)方法
  4. 希望有所帮助。

答案 1 :(得分:1)

我通常处理这类场景的方法是在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);
    }
}

然后在View后面的代码中,执行以下方法:

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);
   }
}   

使用这种方法,您仍然可以保留视图与ViewModel的隔离。当[unit]测试VM时,委托和点在传递给方法时可能为null。然后if块会阻止&#34; UI&#34;被测试的逻辑。

您需要注意的一件事是,如果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);
    }
}

答案 2 :(得分:0)

视图模型应该公开您的视图需要显示和交互的数据和行为,它应该永远不会引用View本身。

View隐式或显式地具有对ViewModel的引用。通过此引用,您可以调用方法,绑定数据,挂钩事件等...

为了简单起见,在这种情况下,您可能希望在用户双击控件时在ViewModel上执行命令,然后可以在命令执行中修改ViewModel公开的任何公共属性。然后可以使用这些属性来确定要缩放的点。