从ViewModel C#访问GUI对象方法

时间:2020-05-21 14:00:24

标签: c# wpf mvvm viewmodel

我正在尝试在图表上创建“假”拖动动画。目的是允许用户通过拖动来手动编辑图中的点。

这个想法非常简单:我在图的顶部放了一个画布,然后单击图的一个点,在单击的标记值上会看到一个红色的圆圈,以及上一行和下一行的两行图点。我“只是”必须将每种形状的不透明度从0设置为1,并指定其位置(XAML代码):

<Canvas Name="GraphOverlay" Grid.Row="1">
    <Ellipse Canvas.Left="{Binding ElipseCanvasLeft}" Canvas.Top="{Binding ElipseCanvasTop}" Stroke="{Binding ShapesColor}" StrokeThickness="6" Width="10" Height="10" Opacity="{Binding ShapesOpacity}"/>
    <Line X1="{Binding leftX1}" X2="{Binding leftX2}" Y1="{Binding leftY1}" Y2="{Binding leftY2}" Stroke="{Binding ShapesColor}"  StrokeThickness="3" Opacity="{Binding ShapesOpacity}"/>
    <Line X1="{Binding rightX1}" X2="{Binding rightX2}" Y1="{Binding rightY1}" Y2="{Binding rightY2}" Stroke="{Binding ShapesColor}"  StrokeThickness="3" Opacity="{Binding ShapesOpacity}"/>
</Canvas>

到目前为止,我可以轻松地从单击的点以及图形的上一个点和下一个点获取图形值。但是,要定义每个形状在腔上的位置(1个圆和2条线),我需要将这些图形值转换为实际像素值。对于圈子,我只需要在用户单击时获取鼠标位置即可。我正在使用这个:

<i:Interaction.Behaviors>
    <utility:MouseBehaviour MouseX="{Binding PanelX, Mode=OneWayToSource}" MouseY="{Binding PanelY, Mode=OneWayToSource}"/>
</i:Interaction.Behaviors>

还有MouseBehaviour类:

public class MouseBehaviour : System.Windows.Interactivity.Behavior<FrameworkElement>
{
    public static readonly DependencyProperty MouseYProperty = DependencyProperty.Register(
        "MouseY", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));

    public double MouseY
    {
        get { return (double)GetValue(MouseYProperty); }
        set { SetValue(MouseYProperty, value); }
    }

    public static readonly DependencyProperty MouseXProperty = DependencyProperty.Register(
        "MouseX", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));

    public double MouseX
    {
        get { return (double)GetValue(MouseXProperty); }
        set { SetValue(MouseXProperty, value); }
    }

    protected override void OnAttached()
    {
        AssociatedObject.MouseMove += AssociatedObjectOnMouseMove;
    }

    private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
    {
        var pos = mouseEventArgs.GetPosition(AssociatedObject);
        MouseX = pos.X;
        MouseY = pos.Y;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.MouseMove -= AssociatedObjectOnMouseMove;
    }
}

PanelXPanelY是ViewModel的两个属性。 Source

但是,我一直在努力获取上一点和下一点的像素坐标。 On livechart's website,有一个示例显示了如何同时使用commandsevents访问图形值。但是,使用事件时,他们可以访问与图表对象关联的ConvertToPixels方法。我无法从viewmodel中访问此方法。

有没有解决的方法,还是应该手动编写该方法?

编辑:这是一张图片,显示我的目标是什么,“下一个点”,“上一个点”是什么意思,...希望对您有帮助!

Don't pay attention to both red areas on top and bottom of the graph

2 个答案:

答案 0 :(得分:1)

我找到了一个解决方案,我真的不知道这有多丑,但是它使我的代码隐藏得很好而且空白。

(非常)丑陋,永远不要通过代码审查:)

您的视图模型现在不仅依赖于App类,而且还依赖于特定窗口中的特定控件,该特定窗口必须存在于屏幕上,代码才能起作用。例如,这将永远不会在单元测试中起作用,并且会严重破坏MVVM模式。

您应该使用接口注入视图模型,并使用该接口与视图进行交互。如果您有兴趣,可以使用here的示例。

答案 1 :(得分:0)

我找到了一个解决方案,我真的不知道这有多么丑陋,但是它使我的代码隐藏得很好而且空白。

要访问该UI元素,必须先在XAML中将其命名:

<lvc:CartesianChart Name="Chart" >
...
</lvc:CartesianChart>

然后在您的应用程序窗口中查找它:

var MyChart = App.Current.Windows[0].FindName("Chart") as Chart;

Windows[0]很难被硬编码,但这确实可以解决问题。