如何在视图模型中获取鼠标位置

时间:2015-05-05 08:06:57

标签: c# wpf mvvm

从MVVM设计模式,viewmodel不应该知道视图。但就我而言,我需要视图和模型,我的意思是:

在我的窗口中,我有一个Image组件。当鼠标移过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光框架

3 个答案:

答案 0 :(得分:7)

我会在这里使用附加行为。这将允许您连续监视鼠标位置,而不是简单地响应MouseDown等事件。您需要添加对var http = require("http"); var iconv = require('iconv-lite'); var zlib = require('zlib'); var fs=require('fs'); var url="http://www.zhihu.com"; var gunzipStream = zlib.createGunzip(); var toWrite=fs.WriteStream("zhihu.html"); function download(url, callback) { http.get(url, function(res) { if(res.headers['content-encoding'].indexOf('gzip') != -1) { res.pipe(gunzipStream).pipe(toWrite); } var data = ""; res.on('data', function (chunk) { data += chunk; }); res.on("end", function() { callback(data); }); }).on("error", function() { callback(null); }); } download(url, function(data) { if (data) { console.log("ץȡԉ٦á"); } else console.log("error"); });程序集的引用。

下面的代码提供了一个简单的示例。

XAML

System.Windows.Interactivity

请注意,在上面的XAML中,MouseBehaviour通过OneWayToSource绑定将鼠标位置向下推到ViewModel,而两个TextBlocks正在从ViewModel读取鼠标位置。

视图模型

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

附加行为

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

答案 1 :(得分:6)

最终使用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>

答案 2 :(得分:3)

Mark Greens解决方案是最好的(我发现)。

如果你想让他的解决方案可以重用于任何WPF控件(我建议),继承System.Windows.Interactivity.Behavior<Control>实际上不适用于Panel,因为Panel不会继承Control。 只有那些类继承自Controlhttps://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进行了测试。

我使用它来保持Popup与鼠标光标同步:

<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}"/>

P.S。:我会对解决方案发表评论,但我的答案太长了。