C# 在MVVM中处理MouseEnter over命令

C# 在MVVM中处理MouseEnter over命令,c#,wpf,xaml,mvvm,command,C#,Wpf,Xaml,Mvvm,Command,我有一个带有ItemControl的画布,填充在带有自定义UserControlViewModels的ViewModel中。我想给每个用户控件一个MouseEnter命令之类的东西 我的ViewModel的XAML如下所示: <Canvas x:Name="gameFieldCanvas" Width="{Binding CanvasWidth}" Height="{Binding CanvasHeight}"> <ItemsControl ItemsSource="{B

我有一个带有ItemControl的画布,填充在带有自定义UserControlViewModels的ViewModel中。我想给每个用户控件一个MouseEnter命令之类的东西

我的ViewModel的XAML如下所示:

<Canvas x:Name="gameFieldCanvas" Width="{Binding CanvasWidth}" Height="{Binding CanvasHeight}">
   <ItemsControl ItemsSource="{Binding GameFieldContent}">
      <ItemsControl.ItemTemplate>
         <DataTemplate DataType="{x:Type local:GameFieldTileViewModel}">
             <Canvas>
                <local:GameFieldTileUserControl X="{Binding TileX}" Y="{Binding TileY}">
                   <local:GameFieldTileUserControl.InputBindings>
                      <MouseBinding MouseAction="LeftClick"
                                                  Command="{Binding DataContext.OnGameFieldTileLeftClicked, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                                                  CommandParameter="{Binding}"/>
                      <MouseBinding MouseAction="RightClick" Command="{Binding DataContext.OnGameFieldTileRightClicked, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                                                  CommandParameter="{Binding}"/>
                   </local:GameFieldTileUserControl.InputBindings>
                </local:GameFieldTileUserControl>
             </Canvas>
         </DataTemplate>
      </ItemsControl.ItemTemplate>
   </ItemsControl>
</Canvas>

就像你可以看到的,我已经用左键/右键点击这个命令了。但是mouseenterements没有输入绑定

我已经读过关于Blend SDK的文章,在那里你可以编写EventTriggers或者类似的东西,但是这不可能用board工具吗


我只想知道当输入一个UserControl时,如何获取它的UserControlViewModel。

你能告诉我你最后想要完成什么吗?我可能有一个更好的答案给你,这取决于你,但你可以,我有很多次,覆盖现有的控制和添加命令属性需要

这是一个自定义用户控件,它具有鼠标移动命令

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WPF_Question_Answer_App
{
    public partial class MouseMoveCommandUserControl : UserControl
    {
        public MouseMoveCommandUserControl()
        {
            InitializeComponent();
            MouseMove += (s, e) =>
            {
                if (MouseMoveCommand?.CanExecute(MouseMoveCommandParameter) ?? false)
                    MouseMoveCommand.Execute(MouseMoveCommandParameter);
            };
        }

        public ICommand MouseMoveCommand
        {
            get => (ICommand)GetValue(MouseMoveCommandProperty);
            set => SetValue(MouseMoveCommandProperty, value);
        }

        public static readonly DependencyProperty MouseMoveCommandProperty =
            DependencyProperty.Register(nameof(MouseMoveCommand), typeof(ICommand), typeof(MouseMoveCommandUserControl), new PropertyMetadata(null));

        public object MouseMoveCommandParameter
        {
            get => GetValue(MouseMoveCommandParameterProperty);
            set => SetValue(MouseMoveCommandParameterProperty, value);
        }

        public static readonly DependencyProperty MouseMoveCommandParameterProperty =
            DependencyProperty.Register(nameof(MouseMoveCommandParameter), typeof(object), typeof(MouseMoveCommandUserControl), new PropertyMetadata(null));
    }
}
这是在视图中使用的,这是显而易见的

<Window x:Class="WPF_Question_Answer_App.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_Question_Answer_App"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:MouseMoveCommandUserControl MouseMoveCommand="{Binding SomeMouseMoveCommand}"
                                           MouseMoveCommandParameter="{Binding SomeMouseMoveCommandParameter}"/>
    </Grid>
</Window>


希望这有助于。。。如果没有,我会删除答案,请告诉我。

你能详细告诉我你最后想要完成什么吗?我可能有一个更好的答案给你,这取决于你,但你可以,我有很多次,覆盖现有的控制和添加命令属性需要

这是一个自定义用户控件,它具有鼠标移动命令

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WPF_Question_Answer_App
{
    public partial class MouseMoveCommandUserControl : UserControl
    {
        public MouseMoveCommandUserControl()
        {
            InitializeComponent();
            MouseMove += (s, e) =>
            {
                if (MouseMoveCommand?.CanExecute(MouseMoveCommandParameter) ?? false)
                    MouseMoveCommand.Execute(MouseMoveCommandParameter);
            };
        }

        public ICommand MouseMoveCommand
        {
            get => (ICommand)GetValue(MouseMoveCommandProperty);
            set => SetValue(MouseMoveCommandProperty, value);
        }

        public static readonly DependencyProperty MouseMoveCommandProperty =
            DependencyProperty.Register(nameof(MouseMoveCommand), typeof(ICommand), typeof(MouseMoveCommandUserControl), new PropertyMetadata(null));

        public object MouseMoveCommandParameter
        {
            get => GetValue(MouseMoveCommandParameterProperty);
            set => SetValue(MouseMoveCommandParameterProperty, value);
        }

        public static readonly DependencyProperty MouseMoveCommandParameterProperty =
            DependencyProperty.Register(nameof(MouseMoveCommandParameter), typeof(object), typeof(MouseMoveCommandUserControl), new PropertyMetadata(null));
    }
}
这是在视图中使用的,这是显而易见的

<Window x:Class="WPF_Question_Answer_App.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_Question_Answer_App"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:MouseMoveCommandUserControl MouseMoveCommand="{Binding SomeMouseMoveCommand}"
                                           MouseMoveCommandParameter="{Binding SomeMouseMoveCommandParameter}"/>
    </Grid>
</Window>


希望这有助于。。。如果没有,我将删除答案,请告诉我。

这只是一个如何使用内置组件实现的示例

您可以利用已经存在的UI组件来实现大部分目标。有副作用(不能连续两次单击同一个平铺,需要修改选择行为等),但这是另一种方式

在窗口中,使用带有适当面板的列表框。在我的示例中,您可以将此作为tic-tac-toe游戏的基础:

<Window x:Class="TileClicker.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TileClicker"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <ListBox
        ItemsSource="{Binding Tiles}"
        SelectedItem="{Binding SelectedTile}" DisplayMemberPath="Name">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid
                    Rows="3"
                    Columns="3" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Window>
我们的瓷砖由

public class Tile : Notifier
{
    private string _name = "Click me";

    public string Name
    {
        get
        {
            return _name;
        }
        set { _name = value; Notify(); }
    }
}
我们的视图模型使用SelectedItem绑定来知道何时单击了一个平铺,并做出相应的响应

public class ViewModel : Notifier
{
    private Tile _tile;
    public ObservableCollection<Tile> Tiles { get; } = new ObservableCollection<Tile> {
        new Tile(), new Tile(), new Tile(), 
        new Tile(), new Tile(), new Tile(), 
        new Tile(), new Tile(), new Tile()
    };
    public Tile SelectedTile
    {
        get
        {
            return _tile;
        }
        set
        {
            _tile = value;
            Notify();
            UpdateName(value);
        }
    }

    private void UpdateName(Tile value)
    {
        if(value.Name == "Click me")
            value.Name = "Woot!";
        else
            value.Name = "Click me";
    }
}

这只是一个如何使用内置组件实现的示例

您可以利用已经存在的UI组件来实现大部分目标。有副作用(不能连续两次单击同一个平铺,需要修改选择行为等),但这是另一种方式

在窗口中,使用带有适当面板的列表框。在我的示例中,您可以将此作为tic-tac-toe游戏的基础:

<Window x:Class="TileClicker.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TileClicker"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <ListBox
        ItemsSource="{Binding Tiles}"
        SelectedItem="{Binding SelectedTile}" DisplayMemberPath="Name">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid
                    Rows="3"
                    Columns="3" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Window>
我们的瓷砖由

public class Tile : Notifier
{
    private string _name = "Click me";

    public string Name
    {
        get
        {
            return _name;
        }
        set { _name = value; Notify(); }
    }
}
我们的视图模型使用SelectedItem绑定来知道何时单击了一个平铺,并做出相应的响应

public class ViewModel : Notifier
{
    private Tile _tile;
    public ObservableCollection<Tile> Tiles { get; } = new ObservableCollection<Tile> {
        new Tile(), new Tile(), new Tile(), 
        new Tile(), new Tile(), new Tile(), 
        new Tile(), new Tile(), new Tile()
    };
    public Tile SelectedTile
    {
        get
        {
            return _tile;
        }
        set
        {
            _tile = value;
            Notify();
            UpdateName(value);
        }
    }

    private void UpdateName(Tile value)
    {
        if(value.Name == "Click me")
            value.Name = "Woot!";
        else
            value.Name = "Click me";
    }
}

感谢您提供代码。我必须编写一个应用程序来用Tiles(
GameFieldTileViewModel
)构建地图。初始地图将填充
草地地砖
。另外,我还有一个包装袋,里面装满了可能要放置的瓷砖(
PlaseableObject
)。单击其中一个
PlaseableObject
后,我生成一个新的
GameFieldTileViewModel
并将其添加到我的
GameFieldContent
集合中。现在我想将其X/Y坐标更改为我用鼠标输入的
GrassfieldTiles
的X/Y坐标,因此,我希望有一个
MouseEnterCommand
,将输入的Tile作为参数。如果要添加到WrapPanel中的控件是PlaseableObject或GrassfieldTiles,并且希望在这些控件上有一个MouseMoveCommand,那么只需将我上面给出的DependencyProperties复制并粘贴到这些控件中即可。然后在构造函数中添加MouseMove事件以尝试触发该命令,并最终将该命令绑定到控件,就像绑定任何其他普通命令一样。当鼠标在控件中移动时,命令将启动(或测试启动)。是的,但是如何将
GameFieldTileViewModel
绑定到
MouseMoveCommandParameter
?当我像在
MouseBinding
中那样做时,我在
if(MouseMoveCommand.CanExecute(MouseMoveCommand参数))
中得到
NullReferenceException
!现在我有了!我忘了什么!非常感谢。你保护了我的一天!=)又来了!我成功地复制了您的mouseweel代码,我需要如何自定义该代码以通过命令获得mouseweel的方向?感谢您提供代码。我必须编写一个应用程序来用Tiles(
GameFieldTileViewModel
)构建地图。初始地图将填充
草地地砖
。另外,我还有一个包装袋,里面装满了可能要放置的瓷砖(
PlaseableObject
)。单击其中一个
PlaseableObject
后,我生成一个新的
GameFieldTileViewModel
并将其添加到我的
GameFieldContent
集合中。现在我想将其X/Y坐标更改为我用鼠标输入的
GrassfieldTiles
的X/Y坐标,因此,我希望有一个
MouseEnterCommand
,将输入的Tile作为参数。如果要添加到WrapPanel中的控件是PlaseableObject或GrassfieldTiles,并且希望在这些控件上有一个MouseMoveCommand,那么只需将我上面给出的DependencyProperties复制并粘贴到这些控件中即可。然后在构造函数中添加MouseMove事件以尝试触发该命令,并最终将该命令绑定到控件,就像绑定任何其他普通命令一样。当鼠标在控件中移动时,命令将启动(或测试启动)。是的,但是如何将
GameFieldTileViewModel
绑定到
MouseMoveCommandParameter
?当我像在
MouseBinding
I中那样做时