0

次の問題についてあなたのアドバイスが必要です:

ルーティング イベント IsSelectedChanged を定義する MyView 型 (UserControl) があるとします。myView.IsSelected プロパティ値が変更されるたびに発生します。

また、非常に (非常に!) 多数のタイプ MyView の子を含む MyContainer (キャンバス) があります。MyContainer にはルーティング イベント MyViewsSelectionChanged があり、MyViewsSelection が変更されるたびに発生します。MyViewsSelection は、 IsSelected プロパティがtrueに設定されている MyView オブジェクトのセットです。MyContainer は、すべての子の MyView.IsSelectedChanged を処理し、その MyViewSelection ステータスを MyContainerParent (パネル) に提供します。

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 (マイコンテナ):

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);
                }
            }
        }));
    }
4

2 に答える 2

0

処理する必要のあるイベントの数が心配な場合。アプローチを再評価する必要があります。ユーザーがアイテムの選択をいつ終了したかを判断する方法はありますか?

イベントの数を減らす方法がない場合は、スロットルを実装することをお勧めします。つまり、一定時間イベントを受信しなかった場合にのみイベントを処理します。

これは、タイマーを使用するなどして自分で実装することも、リアクティブエクステンション(RX)スロットル機能を使用することもできます。

スロットル「指定されたソースとdueTimeの期限前に別の値が続く監視可能なシーケンスからの値を無視します」

RXはhttp://msdn.microsoft.com/en-us/data/gg577609.aspxにあり、Trottleのドキュメントはhttp://msdn.microsoft.com/en-us/library/hh229298%28vにあります。 = vs.103%29。もちろん、NuGetを介してRXをインストールすることもできます。

于 2012-09-14T11:47:05.243 に答える
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

ダンとオバリックス、お時間とご配慮をありがとうございました!

于 2012-09-14T16:38:58.510 に答える