簡體   English   中英

如何在視圖模型中獲取鼠標位置

[英]How do I get mouse positions in my view model

根據MVVM設計模式,視圖模型不應了解視圖。 但就我而言,我需要視圖和模型,我的意思是:

在我的窗口中,有一個圖像組件。 當鼠標移到Image組件上並將其保存到模型中時,我想獲取鼠標位置。

后面的代碼是:

void Foo_MouseMove(objet sender, MouseEventArgs e)
{
  model.x = e.getPosition(this.imageBox).X; 
  model.y = e.getPosition(this.imageBox).Y;
}

問題是:我需要this.imageBox和MouseEventArgs,所以需要兩個View元素。

我的問題是:如何使用MVVM方法處理這種情況?

我使用MVVM light框架

我將在此處使用附加行為。 這將使您能夠連續監視鼠標位置,而不是簡單地響應諸如MouseDown之類的事件。 您需要添加對System.Windows.Interactivity程序集的引用。

下面的代碼提供了一個實際的簡單示例。

XAML

<Window x:Class="MouseMoveMvvm.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:mouseMoveMvvm="clr-namespace:MouseMoveMvvm"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DockPanel>
            <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
                <TextBlock Text="{Binding PanelX, StringFormat='X={0}'}" />
                <TextBlock Text="{Binding PanelY, StringFormat='y={0}'}" />
            </StackPanel>
            <Canvas DockPanel.Dock="Bottom" Background="Aqua">
                <i:Interaction.Behaviors>
                    <mouseMoveMvvm:MouseBehaviour MouseX="{Binding PanelX, Mode=OneWayToSource}" MouseY="{Binding PanelY, Mode=OneWayToSource}" />
                </i:Interaction.Behaviors>
            </Canvas>
        </DockPanel>
    </Grid>
</Window>

請注意,在上述XAML中,MouseBehaviour通過OneWayToSource綁定將鼠標位置向下推到ViewModel,而兩個TextBlocks從ViewModel讀取鼠標位置。

視圖模型

public class MainWindowViewModel : INotifyPropertyChanged
{
    private double _panelX;
    private double _panelY;
    public event PropertyChangedEventHandler PropertyChanged;

    public double PanelX
    {
        get { return _panelX; }
        set
        {
            if (value.Equals(_panelX)) return;
            _panelX = value;
            OnPropertyChanged();
        }
    }

    public double PanelY
    {
        get { return _panelY; }
        set
        {
            if (value.Equals(_panelY)) return;
            _panelY = value;
            OnPropertyChanged();
        }
    }


    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

依附行為

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

最后使用EventConverter找到了答案:

  public class MouseButtonEventArgsToPointConverter : IEventArgsConverter
    {
        public object Convert(object value, object parameter)
        {
            var args = (MouseEventArgs)value;
            var element = (FrameworkElement)parameter;
            var point = args.GetPosition(element);
            return point;
        }
    }

這個轉換器使我可以處理Point而不是圖形組件。

XML來了:

        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseMove">
                <cmd:EventToCommand
                 Command="{Binding Main.MouseMoveCommand, Mode=OneWay}"
                 EventArgsConverter="{StaticResource MouseButtonEventArgsToPointConverter}"
                 EventArgsConverterParameter="{Binding ElementName=Image1}"
                 PassEventArgsToCommand="True" />
            </i:EventTrigger>
        </i:Interaction.Triggers>

Mark Greens解決方案是最好的(我發現)。

如果要使他的解決方案可用於任何WPF控件(我建議),則從System.Windows.Interactivity.Behavior<Control>繼承實際上不適用於Panel ,因為Panel不能從Control繼承。 僅那些類從Control繼承: https : //msdn.microsoft.com/de-de/library/system.windows.controls.control(v=vs.110).aspx

而是從System.Windows.Interactivity.Behavior<FrameworkElement>繼承。 FrameworkElement是所有WPF控件類的始祖: https : //msdn.microsoft.com/de-de/library/system.windows.frameworkelement(v=vs.110).aspx 我已經在GridPanelImage btw上對其進行了測試。

我使用它使彈出窗口與鼠標光標保持同步:

<Image x:Name="Image1">        
  <i:Interaction.Behaviors>
    <myNamespace:MouseBehaviour
      MouseX="{Binding ElementName=Popup1, Path=HorizontalOffset, Mode=OneWayToSource}"
      MouseY="{Binding ElementName=Popup1, Path=VerticalOffset, Mode=OneWayToSource}">
    </myNamespace:MouseBehaviour>
  </i:Interaction.Behaviors>
</Image>

<Popup x:Name="Popup1" PlacementTarget="{Binding ElementName=Image1}"/>

PS:我會對解決方案發表評論,但是我的回答太長了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM