C# 使用MVVM在WPF中相对于图像的鼠标位置

C# 使用MVVM在WPF中相对于图像的鼠标位置,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,在wpf应用程序中,当鼠标位于图像上方时,我尝试在获取鼠标位置时遵循MVVM结构。鼠标位置应转换为相对于图像的像素位置 当Image_MouseMove位于ImagePositionView.xaml.cs中时,我就可以使用它了,但对于如何使用MVVM结构实现这一点,我有点不知所措(即使在尝试读取其他线程之后) 我添加了一个对MVVMLight的引用,希望这将使这项任务更容易,但我以前从未使用过 这就是我到目前为止所做的: 视图: 根据我所看到的,我添加了这些参考资料: xmlns:i=”htt

在wpf应用程序中,当鼠标位于图像上方时,我尝试在获取鼠标位置时遵循MVVM结构。鼠标位置应转换为相对于图像的像素位置

当Image_MouseMove位于ImagePositionView.xaml.cs中时,我就可以使用它了,但对于如何使用MVVM结构实现这一点,我有点不知所措(即使在尝试读取其他线程之后)

我添加了一个对MVVMLight的引用,希望这将使这项任务更容易,但我以前从未使用过

这就是我到目前为止所做的:

视图:

根据我所看到的,我添加了这些参考资料:

xmlns:i=”http://schemas.microsoft.com/expression/2010/interactivity“
xmlns:cmd=”http://www.galasoft.ch/mvvmlight“


我想主要的问题是如何从
ImagePositionViewModel
中访问view元素
ImageOnDisplay
,我是通过一种行为来实现的。首先,我声明我的视图模型将实现的接口:

public interface IMouseCaptureProxy
{
    event EventHandler Capture;
    event EventHandler Release;

    void OnMouseDown(object sender, MouseCaptureArgs e);
    void OnMouseMove(object sender, MouseCaptureArgs e);
    void OnMouseUp(object sender, MouseCaptureArgs e);
}

public class MouseCaptureArgs
{
    public double X {get; set;}
    public double Y { get; set; }
    public bool LeftButton { get; set; }
    public bool RightButton { get; set; }
}
下面是一个使用它的行为:

public class MouseCaptureBehavior : Behavior<FrameworkElement>
{
    public static readonly DependencyProperty ProxyProperty = DependencyProperty.RegisterAttached(
        "Proxy",
        typeof(IMouseCaptureProxy),
        typeof(MouseCaptureBehavior),
        new PropertyMetadata(null, OnProxyChanged));

    public static void SetProxy(DependencyObject source, IMouseCaptureProxy value)
    {
        source.SetValue(ProxyProperty, value);
    }

    public static IMouseCaptureProxy GetProxy(DependencyObject source)
    {
        return (IMouseCaptureProxy)source.GetValue(ProxyProperty);
    }

    private static void OnProxyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue is IMouseCaptureProxy)
        {
            (e.OldValue as IMouseCaptureProxy).Capture -= OnCapture;
            (e.OldValue as IMouseCaptureProxy).Release -= OnRelease;
        }
        if (e.NewValue is IMouseCaptureProxy)
        {
            (e.NewValue as IMouseCaptureProxy).Capture += OnCapture;
            (e.NewValue as IMouseCaptureProxy).Release += OnRelease;
        }
    }

    static void OnCapture(object sender, EventArgs e)
    {
        var behavior = sender as MouseCaptureBehavior;
        if (behavior != null)
            behavior.AssociatedObject.CaptureMouse();
    }

    static void OnRelease(object sender, EventArgs e)
    {
        var behavior = sender as MouseCaptureBehavior;
        if (behavior != null)
            behavior.AssociatedObject.ReleaseMouseCapture();
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.PreviewMouseDown += OnMouseDown;
        this.AssociatedObject.PreviewMouseMove += OnMouseMove;
        this.AssociatedObject.PreviewMouseUp += OnMouseUp;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.PreviewMouseDown -= OnMouseDown;
        this.AssociatedObject.PreviewMouseMove -= OnMouseMove;
        this.AssociatedObject.PreviewMouseUp -= OnMouseUp;
    }

    private void OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        var proxy = GetProxy(this);
        if (proxy != null)
        {
            var pos = e.GetPosition(this.AssociatedObject);
            var args = new MouseCaptureArgs {
                X = pos.X,
                Y = pos.Y,
                LeftButton = (e.LeftButton == MouseButtonState.Pressed),
                RightButton = (e.RightButton == MouseButtonState.Pressed)
            };
            proxy.OnMouseDown(this, args);
        }
    }

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        var proxy = GetProxy(this);
        if (proxy != null)
        {
            var pos = e.GetPosition(this.AssociatedObject);
            var args = new MouseCaptureArgs {
                X = pos.X,
                Y = pos.Y,
                LeftButton = (e.LeftButton == MouseButtonState.Pressed),
                RightButton = (e.RightButton == MouseButtonState.Pressed)
            };
            proxy.OnMouseMove(this, args);
        }
    }

    private void OnMouseUp(object sender, MouseButtonEventArgs e)
    {
        var proxy = GetProxy(this);
        if (proxy != null)
        {
            var pos = e.GetPosition(this.AssociatedObject);
            var args = new MouseCaptureArgs
            {
                X = pos.X,
                Y = pos.Y,
                LeftButton = (e.LeftButton == MouseButtonState.Pressed),
                RightButton = (e.RightButton == MouseButtonState.Pressed)
            };
            proxy.OnMouseUp(this, args);
        }
    }

}

更新:这应该是不言而喻的,但以防万一:传递给捕获和释放事件的发送方应该与通过MouseDown/Move/Up处理程序接收到的发送方相同。传递给捕获/接收的事件参数不使用,可以为空。

当鼠标使用MVVM在图像上移动时,加载图像并用rgb值显示其xy坐标的解决方案。。 希望这对一些人有帮助

视图模型:

class MainWindowViewModel : ViewModelBase
{
    private Bitmap Img; 
    public ICommand OpenImg { get; set; }
    public MainWindowViewModel()
    {
        OpenImg = new RelayCommand(openImg, (obj) => true);
    }       
    private void openImg(object obj = null)
    {
        OpenFileDialog op = new OpenFileDialog();
        op.Title = "Select a picture";
        op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png;*.bmp;*.tiff|" +
          "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
          "Portable Network Graphic (*.png)|*.png";
        if (op.ShowDialog() == true)
        {
            ImgPath = op.FileName;
            Img = new Bitmap(ImgPath);
        }
    }

    private string _ImgPath;
    public string ImgPath
    {
        get
        {
            return _ImgPath;
        }
        set
        {
            _ImgPath = value;
            OnPropertyChanged("ImgPath");
        }
    }

    private ICommand _mouseMoveCommand;
    public ICommand MouseMoveCommand
    {
        get
        {
            if (_mouseMoveCommand == null)
            {
              _mouseMoveCommand = new RelayCommand(param => ExecuteMouseMove((MouseEventArgs)param));
            }      
            return _mouseMoveCommand;
        }
        set { _mouseMoveCommand = value; }
    }
    private void ExecuteMouseMove(MouseEventArgs e)
    {
        System.Windows.Point p = e.GetPosition(((IInputElement)e.Source));
        XY = String.Format("X: {0} Y:{1}", (int)p.X, (int)p.Y);

        BitmapData bd = Img.LockBits(new Rectangle(0, 0, Img.Width, Img.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        unsafe
        {
            byte* ptr = (byte*)bd.Scan0;
            int x = (int)p.X * 3;
            int y = (int)p.Y * bd.Stride;
            RGB = "R: "+ptr[x + y + 2].ToString() + " G: " + ptr[x + y + 1].ToString() + " B: " + ptr[x + y].ToString();
        }
        Img.UnlockBits(bd);
    }
    private string xy;
    public string XY
    {
        get { return xy; }
        set
        {
            xy = value;
            OnPropertyChanged("XY");
        }
    }
    private string rgb;
    public string RGB
    {
        get { return rgb; }
        set
        {
            rgb = value;
            OnPropertyChanged("RGB");
        }
    }
}
MainWindow.xaml

<Window.Resources>
    <vm:MainWindowViewModel x:Key="MainWindowViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource MainWindowViewModel}">
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*" />
        <RowDefinition Height="25"/>
    </Grid.RowDefinitions>
    <Grid Grid.Row="0">
        <Menu FontSize="20">
            <MenuItem Header="File">
                <MenuItem Header="Open" Command="{Binding OpenImg}"/>
            </MenuItem>
        </Menu>
    </Grid>
    <Grid Grid.Row="1" Background="LightGray">
        <Viewbox Margin="3,3,3,3">
                    <Image x:Name="img" Stretch="None" Source="{Binding ImgPath}"
                           Model:MouseBehaviour.MouseMoveCommand="{Binding MouseMoveCommand}">     
                    </Image>
        </Viewbox>
    </Grid>
    <Grid Grid.Row="2">
        <StackPanel Orientation="Horizontal">
            <TextBox Focusable="False" Text="{Binding XY}" Width="100"/>
            <TextBox Focusable="False" Text="{Binding RGB}" Width="115"/>
        </StackPanel>
    </Grid>
</Grid>


在ViewModel中使用视图类型违反了MVVM模式,这正是OP要求避免的。@Tseng我没有使用任何视图类型,再次查看我的代码。查看MSDN并查看哪个程序集
MouseCaptureArgs
defined@Tseng我没有在视图模型中使用.NET MouseCaptureArgs类,只是在行为中使用。再看看我的代码,我的错。不过,这是次优解决方案。最好改用附加属性,它们可以通过数据绑定直接绑定(即使用
Rect
Point
so),并避免使用依赖于绑定到行为的接口的过于具体的实现。然后,您可以将任何viewmodel绑定到它,而无需引用/实现该接口。对于更复杂的需求,通过dependencies属性扩展
ImageView
可能更合适模型:示例中缺少鼠标行为
<!-- Canvas must have a background, even if it's Transparent -->
<Canvas Background="White" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
    <i:Interaction.Behaviors>
        <behaviors:MouseCaptureBehavior Proxy="{Binding}" />
    </i:Interaction.Behaviors>
public class MainViewModel : ViewModelBase, IMouseCaptureProxy
{
    public event EventHandler Capture;
    public event EventHandler Release;

    public void OnMouseDown(object sender, MouseCaptureArgs e) {...}
    public void OnMouseMove(object sender, MouseCaptureArgs e) {...}
    public void OnMouseUp(object sender, MouseCaptureArgs e) {...}
}
class MainWindowViewModel : ViewModelBase
{
    private Bitmap Img; 
    public ICommand OpenImg { get; set; }
    public MainWindowViewModel()
    {
        OpenImg = new RelayCommand(openImg, (obj) => true);
    }       
    private void openImg(object obj = null)
    {
        OpenFileDialog op = new OpenFileDialog();
        op.Title = "Select a picture";
        op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png;*.bmp;*.tiff|" +
          "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
          "Portable Network Graphic (*.png)|*.png";
        if (op.ShowDialog() == true)
        {
            ImgPath = op.FileName;
            Img = new Bitmap(ImgPath);
        }
    }

    private string _ImgPath;
    public string ImgPath
    {
        get
        {
            return _ImgPath;
        }
        set
        {
            _ImgPath = value;
            OnPropertyChanged("ImgPath");
        }
    }

    private ICommand _mouseMoveCommand;
    public ICommand MouseMoveCommand
    {
        get
        {
            if (_mouseMoveCommand == null)
            {
              _mouseMoveCommand = new RelayCommand(param => ExecuteMouseMove((MouseEventArgs)param));
            }      
            return _mouseMoveCommand;
        }
        set { _mouseMoveCommand = value; }
    }
    private void ExecuteMouseMove(MouseEventArgs e)
    {
        System.Windows.Point p = e.GetPosition(((IInputElement)e.Source));
        XY = String.Format("X: {0} Y:{1}", (int)p.X, (int)p.Y);

        BitmapData bd = Img.LockBits(new Rectangle(0, 0, Img.Width, Img.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        unsafe
        {
            byte* ptr = (byte*)bd.Scan0;
            int x = (int)p.X * 3;
            int y = (int)p.Y * bd.Stride;
            RGB = "R: "+ptr[x + y + 2].ToString() + " G: " + ptr[x + y + 1].ToString() + " B: " + ptr[x + y].ToString();
        }
        Img.UnlockBits(bd);
    }
    private string xy;
    public string XY
    {
        get { return xy; }
        set
        {
            xy = value;
            OnPropertyChanged("XY");
        }
    }
    private string rgb;
    public string RGB
    {
        get { return rgb; }
        set
        {
            rgb = value;
            OnPropertyChanged("RGB");
        }
    }
}
<Window.Resources>
    <vm:MainWindowViewModel x:Key="MainWindowViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource MainWindowViewModel}">
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*" />
        <RowDefinition Height="25"/>
    </Grid.RowDefinitions>
    <Grid Grid.Row="0">
        <Menu FontSize="20">
            <MenuItem Header="File">
                <MenuItem Header="Open" Command="{Binding OpenImg}"/>
            </MenuItem>
        </Menu>
    </Grid>
    <Grid Grid.Row="1" Background="LightGray">
        <Viewbox Margin="3,3,3,3">
                    <Image x:Name="img" Stretch="None" Source="{Binding ImgPath}"
                           Model:MouseBehaviour.MouseMoveCommand="{Binding MouseMoveCommand}">     
                    </Image>
        </Viewbox>
    </Grid>
    <Grid Grid.Row="2">
        <StackPanel Orientation="Horizontal">
            <TextBox Focusable="False" Text="{Binding XY}" Width="100"/>
            <TextBox Focusable="False" Text="{Binding RGB}" Width="115"/>
        </StackPanel>
    </Grid>
</Grid>