我需要针对以下问题进行重新校准:
假设您有一个MyView类型(UserControl),它定义了一个路由事件IsSelectedChanged。每次更改myView.IsSelected属性值时都会引发它。
此外,你有一个MyContainer(Canvas),它包含一个非常(非常!)大量的MyView类型的子节点。 MyContainer已路由事件MyViewsSelectionChanged,每当MyViewsSelection更改时都会引发该事件。 MyViewsSelection是一组MyView对象,其IsSelected属性设置为 true 。 MyContainer将为每个孩子处理MyView.IsSelectedChanged并将其MyViewSelection状态提供给MyContainerParent(Panel)
MyContainerParent将处理myContainer.MyViewsSelectionChanged事件
我担心的问题是我的应用程序对于大量MyView对象的选择性能不佳,导致某种事件的“野火”。
任何预防这一问题的重新定位都将非常感谢!
由于
一些代码:
BatchView.IsSelectedChanged(MyView):
public static readonly RoutedEvent IsSelectedChangedEvent = EventManager.RegisterRoutedEvent(
"IsSelectedChanged",
RoutingStrategy.Direct,
typeof(RoutedEventHandler),
typeof(BatchView)
);
/// <summary>
/// Occurs when IsSelected property value is changed.
/// </summary>
public event RoutedEventHandler IsSelectedChanged {
add { AddHandler(IsSelectedChangedEvent, value); }
remove { RemoveHandler(IsSelectedChangedEvent, value); }
}
void RaiseIsSelectionChangedEvent() {
RoutedEventArgs e = new RoutedEventArgs(IsSelectedChangedEvent, this.BatchViewModel);
RaiseEvent(e);
Logger.Debug("IsSelectionChanged: {0}; IsSelected = {1}", this.BatchViewModel.Description, this.IsSelected);
}
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.RegisterAttached(
"IsSelected",
typeof(bool),
typeof(BatchView),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(delegate(DependencyObject sender, DependencyPropertyChangedEventArgs args) {
BatchView view = sender as BatchView;
bool isSelected = Convert.ToBoolean(args.NewValue);
if ( view != null ) {
view._border.BorderBrush = isSelected ? Brushes.Magenta : Brushes.Black;
view.IsPrimarySelected = view.IsFocused && isSelected;
}
})));
/// <summary>
/// Get/set whether this batch view is selected
/// </summary>
public bool IsSelected {
get { return (bool)GetValue(IsSelectedProperty); }
set {
if ( IsSelected != value ) {
SetValue(IsSelectedProperty, value);
RaiseIsSelectionChangedEvent();
}
}
}
GanttView(MyContainer):
static GanttView() {
EventManager.RegisterClassHandler(typeof(BatchView), BatchView.IsSelectedChangedEvent, new RoutedEventHandler(delegate(object sender, RoutedEventArgs args) {
var batchView = sender as BatchView;
var ganttView = batchView.FindVisualParent<GanttView>();
if ( ganttView != null ) {
ganttView.RaiseBatchViewsSelectionChangedEvent();
}
args.Handled = true;
}));
}
public static readonly RoutedEvent BatchViewsSelectionChangedEvent = EventManager.RegisterRoutedEvent(
"BatchViewsSelectionChanged",
RoutingStrategy.Direct,
typeof(RoutedEventHandler),
typeof(GanttView)
);
public event RoutedEventHandler BatchViewsSelectionChanged {
add { AddHandler(BatchViewsSelectionChangedEvent, value); }
remove { RemoveHandler(BatchViewsSelectionChangedEvent, value); }
}
void RaiseBatchViewsSelectionChangedEvent() {
RoutedEventArgs e = new RoutedEventArgs(BatchViewsSelectionChangedEvent, this);
RaiseEvent(e);
Logger.Debug("BatchViewsSelectionChanged: {0};", this.SelectedBatchViews.Count());
}
SchedulerView(MyContainerParent):
static SchedulerView() {
EventManager.RegisterClassHandler(typeof(GanttView), GanttView.BatchViewsSelectionChangedEvent, new RoutedEventHandler(delegate(object sender, RoutedEventArgs args) {
var schedulerView = ((GanttView)sender).FindVisualParent<SchedulerView>();
if ( schedulerView != null ) {
if ( schedulerView.BatchesSelectionChanged != null ) {
BatchesSelectionChangedEventArgs e = new BatchesSelectionChangedEventArgs();
e.SelectedBatchesCount = schedulerView.GanttView.SelectedBatchViews.Count();
e.TotalBatchesDuration = schedulerView.GanttView.SelectedBatchViews.Sum<BatchView>(bv => bv.BatchViewModel.Model.Duration);
e.TotalBatchesQuantity = schedulerView.GanttView.SelectedBatchViews.Sum<BatchView>(bv => bv.BatchViewModel.Model.Quantity);
schedulerView.BatchesSelectionChanged(schedulerView, e);
}
}
}));
}
答案 0 :(得分:0)
如果您担心必须处理的事件数量。你应该重新评估你的方法。有没有办法确定用户何时完成选择项目?
如果无法减少事件数量,那么您可能希望实施限制,即如果在一定时间内未收到任何事件,则只处理事件。
您可以自己实施 - 例如通过使用计时器 - 或者您可以使用无功扩展'(RX)节流功能。
节流“忽略来自可观察序列的值 在指定源的适当时间之前跟随另一个值 和dueTime“
您可以在http://msdn.microsoft.com/en-us/data/gg577609.aspx找到RX,在http://msdn.microsoft.com/en-us/library/hh229298%28v=vs.103%29找到Trottle的文档。显然你也可以通过NuGet安装RX。
答案 1 :(得分:0)
我想与我的问题分享解决方案。解决方案基于我的经理和Obalix提供的重新授权。所以,我将使用一个计时器,以延迟一点GanttView.BacthViewsSelectionChangedEvent。
static GanttView() {
EventManager.RegisterClassHandler(typeof(BatchView), BatchView.IsSelectedChangedEvent, new RoutedEventHandler(delegate(object sender, RoutedEventArgs args) {
var batchView = sender as BatchView;
var ganttView = batchView.FindVisualParent<GanttView>();
if ( ganttView != null && !ganttView._batchViewIsSelectedChangedEventQueued ) {
ganttView._batchViewIsSelectedChangedEventQueued = true;
System.Timers.Timer eventTrigger = new System.Timers.Timer(100) { AutoReset = false };
eventTrigger.Start();
eventTrigger.Elapsed += new System.Timers.ElapsedEventHandler(delegate(object timer, System.Timers.ElapsedEventArgs e) {
ganttView._batchViewIsSelectedChangedEventQueued = false;
ganttView.Dispatcher.Invoke(new Action(delegate() { ganttView.RaiseBatchViewsSelectionChangedEvent(); }), DispatcherPriority.Normal, null);
});
}
args.Handled = true;
}));
}
使用Dispatcher属性调用ganttView.RaiseBatchViewsSelectionChangedEvent()很重要,否则你会得到一个异常(“调用线程无法访问此对象,因为不同的线程拥有它。”),请参阅这篇文章http://www.switchonthecode.com/tutorials/working-with-the-wpf-dispatcher
Dan和Obalix,非常感谢你的时间和考虑!