C# MVVM模式中的去抖动事件/命令
我正在使用Caliburn.Micro构建一个通用windows应用程序,不幸的是,由于某些硬件限制,我们需要针对windows 10 1607,因此无法实现任何依赖于.NET标准/UWP 16299的软件包,这包括ReactiveUI 在这个特定的场景中,我有一种视图模型优先的方法,它生成一个映射(和一些其他资源),然后将这些映射绑定到XAML视图中的一个映射视图。理想情况下,我希望在通过C# MVVM模式中的去抖动事件/命令,c#,mvvm,uwp,caliburn.micro,C#,Mvvm,Uwp,Caliburn.micro,我正在使用Caliburn.Micro构建一个通用windows应用程序,不幸的是,由于某些硬件限制,我们需要针对windows 10 1607,因此无法实现任何依赖于.NET标准/UWP 16299的软件包,这包括ReactiveUI 在这个特定的场景中,我有一种视图模型优先的方法,它生成一个映射(和一些其他资源),然后将这些映射绑定到XAML视图中的一个映射视图。理想情况下,我希望在通过ViewpointChanged事件移动地图时触发一个进程 查看模型 public class Examp
ViewpointChanged
事件移动地图时触发一个进程
查看模型
public class ExampleViewModel : Screen
{
public ExampleViewModel()
{
Map = new Map();
}
public Map Map { get; set; }
public BindableCollection<MapItems> MapItems { get; set; }
private UpdateMapItems(Envelope visibleArea)
{
// The visibleArea param will include the current viewpoint of the map view
// This method will effectively generate the appropriate map items based on the current coordinates
}
}
公共类示例视图模型:屏幕
{
公共示例ViewModel()
{
Map=新Map();
}
公共映射映射{get;set;}
公共BindableCollection映射项{get;set;}
私有更新包(信封可视区域)
{
//visibleArea参数将包括地图视图的当前视点
//此方法将根据当前坐标有效地生成适当的地图项目
}
}
查看
...
<MapView x:Name="MapView" Map="{Binding Map}" cal:Message.Attach="[Event ViewpointChanged] = [Action UpdateMapItems(MapView.VisibleArea.Extent)]" />
...
。。。
...
现在,这在技术上是可行的,但有一个主要缺陷,即地图的每次移动都会多次触发ViewpointChanged事件(类似于OnMouseMove的效果)
理想情况下,我希望能够限制/取消此事件,以便仅当视图在300ms内未移动时才处理贴图项
我发现一篇文章涉及实现一个dispatchermer
,但是该代码的元素,如DispatcherPriority
和Dispatcher
在UWP中似乎不可用,因此除非存在替代方案,否则我认为这不会起作用
我已经看过这个系统了。反应性的,但对于我想要实现的目标来说,这似乎异常复杂
任何指点都将不胜感激 您可以通过几种方式来实现这一点
油门
操作员可以实现所需的行为
可观察
.FromEventPattern(MapView,名称(ViewpointChanged));
.节气门(时间跨度从毫秒(300));
.Subscribe(eventPattern=>vm.UpdateMapItems(eventPattern.Sender.VisibleArea.Extent));
当使用FromEventPattern
时,我们将事件映射到的实例,其中包括事件的发送方
(源)
我通过订阅UIElement
的PointerMoved
事件进行测试。如果我们继续移动,会多次触发HandleEvent
。但是,对于节流阀
,事件处理程序只执行一次。这是我们停止移动后的间隔时间
MainPage.xaml
MainPage.xaml.cs
公共密封部分类主页面:第页
{
公共主页()
{
this.InitializeComponent();
可观察
.FromEventPattern(MyUIElement,名称(UIElement.PointerMoved))
.节气门(时间跨度从毫秒(300))
.Subscribe(eventPattern=>HandleEvent(eventPattern.Sender,eventPattern.EventArgs));
}
私有void HandleEvent(对象源,PointErrorutedEventArgs args args)
{
Debug.WriteLine(“指针移动”);
}
}
Throttle
类跟踪已处理的最后一个sender
和args
。按照“传递到节流阀进行处理”进行处理。只有当计时器过期且没有发生其他事件时,eventHandler
(作为构造函数参数传递)才会实际执行
公共级油门
{
专用只读调度程序计时器;
私有对象\u lastSender;
私人TEventArgs_lastEventArgs;
公共节流(EventHandler EventHandler,时间间隔)
{
_计时器=新调度程序
{
间隔=间隔
};
_计时器.勾号+=(s,e)=>
{
_timer.Stop();
eventHandler(_lastSender,_lastEventArgs);
};
}
public void ProcessEvent(对象发送方,TEventArgs args)
{
_timer.Stop();
_timer.Start();
_lastSender=发送方;
_lastEventArgs=args;
}
}
MainPage.xaml.cs
公共密封部分类主页面:第页
{
专用只读节流阀_节流阀;
公共主页()
{
this.InitializeComponent();
var interval=时间跨度从毫秒(300);
_节气门=新节气门(扶手通风口,间隔);
MyUIElement.PointerMoved+=(发送方,e)=>\u throttle.ProcessEvent(发送方,e);
}
私有void HandleEvent(对象发送方,PointErroroutedEventArgs e)
{
Debug.WriteLine(“指针移动”);
}
}
更新
我正在努力弄清楚在MVVM环境中,所有东西是如何结合在一起的。事件需要触发的逻辑包含在ViewModel中,但视图和ViewModel应该完全分开
有几件事我想提一下:
- 关于分离关注点的必要性,您是对的,但是许多开发人员不清楚这到底意味着什么。视图模型应该完全不知道谁在听,这是毫无疑问的。但是视图依赖于视图模型来获取其数据,因此视图可以了解视图模型。问题更多的是以松散耦合的方式执行,即使用绑定和契约,而不是直接访问视图模型成员
- 这就是为什么我并不特别喜欢卡利本的行为。使用
cal:Message.Attach
没有将视图语法与视图模型的语法解耦的契约(例如ICommand)。当然,有绑定在起作用,所以您仍然可以获得解耦的MVVM层
长话短说,有一个