代码之家  ›  专栏  ›  技术社区  ›  Qwertie

WPF:如何将鼠标事件附加到视图模型?

  •  6
  • Qwertie  · 技术社区  · 16 年前

    ItemsControl DataTemplate 的;对象是中表示的“节点”和“边” 数据模板 Thumb Polyline 以便移动节点和边。

    两个问题:

    • 如何将鼠标事件处理程序附加到 多段线 的和 是由小viewmodel来处理的吗?(我可以附上 Thumb.DragDelta 处理程序 e.OriginalSource 指向 ,但如何获取相应的viewmodel对象?)
    • 如何将鼠标事件处理程序附加到

    注意:我知道,如果它直接处理View的事件,它可能不会被视为一个合适的ViewModel。但重要的是,我需要处理鼠标事件,我不确定如何附加它们。

    6 回复  |  直到 14 年前
        1
  •  6
  •   Qwertie    16 年前

    我找到了一种处理DataTemplate中对象引发的事件的方法。

    (1) 将事件处理程序附加到Items控件

    <ItemsControl x:Name="_itemsControl" 
                  Thumb.DragStarted="Node_DragStarted"
                  Thumb.DragDelta="Node_DragDelta"
                  Thumb.DragCompleted="Node_DragCompleted"
                  MouseDoubleClick="OnMouseDoubleClick"
                  .../>
    

    (2) 要找出事件应用于哪个项目,请将OriginalSource视为FrameworkElement,并获取其DataContext:

    void Node_DragStarted(object sender, DragStartedEventArgs e)
    {
        var os = (FrameworkElement)e.OriginalSource;
        var vm = os.DataContext as ItemViewModel;
        if (vm != null)
            // do something with the item ViewModel
    }
    
        2
  •  3
  •   Cameron MacFarland    16 年前

    ViewModel应该与GUI断开连接,因此它对控件或鼠标点击一无所知。

    两种选择:

    • 按照Thomas的建议,在ViewModel中调用命令
    • 将拇指的位置绑定到ViewModel中的属性,然后当控件在WPF中移动时,WPF将更新ViewModel中的位置值。
        3
  •  2
  •   Qwertie    16 年前

    我找到了第二个问题的答案。我需要一个支持滚动的items控件,并且我需要将项目放在网格上,而不是默认的StackPanel上。为了满足这两个要求,我使用了ControlTemplate:

    <!--In the resources...-->
    <ControlTemplate x:Key="GraphTemplate" TargetType="ItemsControl">
        <ScrollViewer Name="ScrollViewer"
                      Padding="{TemplateBinding Padding}"
                      HorizontalScrollBarVisibility="Auto">
            ...
                <Grid Name="Panel" IsItemsHost="True"
                      Background="{TemplateBinding ItemsControl.Background}"/>
            ...
        </ScrollViewer>
    </ControlTemplate>
    <!--Later...-->
    <ItemsControl x:Name="_itemsControl" 
                  ItemsSource="{Binding Items}"
                  Template="{StaticResource GraphTemplate}"
                  Background="LightYellow"/>
    

    为了获得具有有意义的鼠标坐标(即可滚动空间中的坐标)的鼠标事件,有必要使用奇怪的咒语获得对网格的引用:

    Grid grid = (Grid)_itemsControl.Template.FindName("Panel", _itemsControl);
    

    然后,您将事件处理程序附加到网格,并在鼠标事件处理程序中,使用以下命令获取鼠标相对于网格的坐标

    Point p = e.GetPosition((IInputElement)sender);
    

    为了在整个表面上获取鼠标事件,控件(实际上是网格)必须有背景,因此我在上面设置了background=“LightYellow”,它通过ControlTemplate中的绑定传播到网格。

        4
  •  1
  •   micahtan    16 年前

    Bea Stollnitz有一个名为“如何在数据绑定的items控件之间拖放项目?”的拖放示例。我本想发布链接,但StackOverflow不让我这么做。

    您可能希望在拖动过程中拆分UI反馈,并在最终拖放时执行操作。

    不过,我同意托马斯和卡梅伦的观点。您需要限制事件处理和数据绑定的混合/匹配。如果你要走事件处理路线,你可能不想避免为你的对象使用“视图模型”一词,因为它通常表示数据绑定的替代方案。

        5
  •  1
  •   Thomas Levesque    11 年前

    有一些方法可以在没有代码的情况下做到这一点。..

    您可以使用附加的行为模式将事件映射到命令,请参阅Marlon Grech的实现 here

    你也可以使用 markup extension 我写的是将InputBindings绑定到ViewModel命令,如下所示:

    <UserControl.InputBindings>
        <MouseBinding Gesture="LeftClick" Command="{input:CommandBinding SomeCommand}"/>
    </UserControl.InputBindings>
    

    但我不确定它是否符合您的具体需求。..

        6
  •  0
  •   Michael Myers KitsuneYMG    15 年前

    我正在使用一种更优雅的方法。我使用Prism 2和数据模板。所以我所做的是:

    <ItemsControl x:Name="SearchImagesList" ItemTemplate="{StaticResource SearchResultsAlbum}"   
    

    在ItemTemplate中,我刚刚在里面创建了一个按钮!

    <DataTemplate x:Key="SearchResultsAlbum">                        
        <Button CommandParameter="{Binding}"                 
                Command="{Binding Source={x:Static PhotoBookPRMainModule:ServiceProvider.DesignEditorViewManager}, Path=NavigationCommands.NavigateSearchResultAction}">