我第一次尝试使用MVVM模式。所以我有ItemsControl
填充了我的viewmodel对象,使用DataTemplate
显示;对象是DataTemplate
中带有Thumb
和Polyline
对象的“节点”和“边缘”,我希望能够检测ItemsControl
上的点击和拖动为了移动节点和边缘。
两个问题:
Polyline
和Thumb
以由小视图模型处理? (我可以将Thumb.DragDelta
处理程序附加到ItemsControl
和e.OriginalSource
指向Thumb
,但是如何获取相应的viewmodel对象?)ItemsControl
以检测空白区域上的鼠标点击和拖动? (答案如下)注意:我知道如果它直接处理View的事件,它可能不被认为是正确的ViewModel。但重要的是,我需要处理鼠标事件,我不知道如何附加它们。
答案 0 :(得分:6)
我找到了一种处理DataTemplate中对象引发的事件的方法。
(1)将事件处理程序附加到ItemsControl
<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
}
答案 1 :(得分:3)
ViewModel应该与GUI断开连接,因此它对控件或鼠标点击没有任何了解。
两个选项:
答案 2 :(得分:2)
我找到了第二个问题的答案。我需要一个支持滚动的ItemsControl,我需要将项目放在网格而不是默认的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);
然后将事件处理程序附加到网格,并在鼠标事件处理程序内部获取鼠标坐标w.r.t.网格使用
Point p = e.GetPosition((IInputElement)sender);
为了在整个表面上获取鼠标事件,控件(实际上是网格)必须有背景,所以我在上面设置Background =“LightYellow”,它通过ControlTemplate中的绑定传播到网格。
答案 3 :(得分:1)
如果没有代码隐藏,有很多方法可以做到这一点......
您可以使用附加的行为模式将事件映射到命令,请参阅Marlon Grech的实现here
您还可以使用我编写的markup extension将InputBindings绑定到ViewModel命令,如下所示:
<UserControl.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{input:CommandBinding SomeCommand}"/>
</UserControl.InputBindings>
但是我不确定它是否符合您的特定需求......
答案 4 :(得分:1)
Bea Stollnitz有一个标题为“如何在数据绑定的ItemsControls之间拖放项目?”的拖放示例。我发布链接,但StackOverflow不允许我。
您可能希望在拖动过程中分割UI反馈,并在最终删除时执行操作。
但是,我同意托马斯和卡梅隆。您需要限制事件处理和数据绑定的混合/匹配。如果您要使用事件处理路径,则可能不希望避免对对象使用术语“视图模型”,因为它通常表示数据绑定替代方案。答案 5 :(得分:0)
我正在使用更优雅的方法。我使用Prism 2和datatemplates。所以我所做的就是:
<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}">