2009-02-10 146 views
14

我需要能够在将对象添加到Queue<Delegate>时触发事件。C#:将对象添加到队列时触发事件

我创建的延伸Queue一个新的类:

public delegate void ChangedEventHandler(object sender, EventArgs e); 

public class QueueWithChange<Delegate> : Queue<Delegate> 
{ 
    public event ChangedEventHandler Changed; 

    protected virtual void OnChanged(EventArgs e) { 
     if (Changed != null) 
     { 
      Changed(this, e); 
     } 
    } 
} 

,然后从另一个类中,像这样的附接的情况下:

QueueWithChange<TimerDelegate> eventQueue = new QueueWithChange<TimerDelegate>(); 

// 

eventQueue.Changed += new ChangedEventHandler(delegate(object s, EventArgs ex) { 
    //This event is not being triggered, so this code is unreachable atm...and that is my problem 

    if (eventQueue.Count > 0) 
    { 
     eventQueue.Dequeue().Invoke(new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(5) }); 
     actionTimer.Stop(); 
    } 
}); 

但每当我排队的对象(eventQueue.Enqueue(something)),附加的事件没有被解雇。

我在这里错过了什么?

回答

25

如果你指的非通用Queue类,那么你可以只覆盖Enqueue

public override void Enqueue(object obj) 
{ 
    base.Enqueue(obj); 
    OnChanged(EventArgs.Empty); 
} 

不过,如果你指的是通用Queue<T>类,然后注意,是覆盖没有合适的虚方法。你可能会做的更好封装队列中有你自己的类:

(**重要编辑:删除基类!!! **)

class Foo<T> 
{ 
    private readonly Queue<T> queue = new Queue<T>(); 
    public event EventHandler Changed; 
    protected virtual void OnChanged() 
    { 
     if (Changed != null) Changed(this, EventArgs.Empty); 
    } 
    public virtual void Enqueue(T item) 
    { 
     queue.Enqueue(item); 
     OnChanged(); 
    } 
    public int Count { get { return queue.Count; } } 

    public virtual T Dequeue() 
    { 
     T item = queue.Dequeue(); 
     OnChanged(); 
     return item;   
    } 
} 

不过,看你的代码,它似乎有可能你在这里使用多个线程。如果是这种情况,请考虑使用threaded queue

+0

优秀;这正是我正在寻找的。感谢马克的质量答案。我还会检查你提到的Threaded Queue。 – 2009-02-10 08:34:58

0

您必须重写Enqueue才能调用OnChanged。

+0

Enqueue在通用队列上不是虚拟的 2009-02-10 08:24:54

+0

对,这太遗憾了。我想你必须创建一个IQueue接口,然后有自己的实现。 – 2009-02-10 08:41:53

1

尝试

public new void Enqueue(Delegate d) 
{ 
    base.Enqueue(d); 
    OnChanged(EventArgs.Empty); 
} 
3

我只是写了我称之为一个TriggeredQueue。这启发了Marc Gravell的答案。

你可以找到我的帖子在这里:http://joesauve.com/triggeredqueuet

而且这里的要点是:http://gist.github.com/jsauve/b2e8496172fdabd370c4

它有四个事件:

  • WillEnqueue
  • WillDequeue
  • DidEnqueue
  • DidDequeue

你可以连接到任何一个像这样:

YourQueue.WillEnqueue += (sender, e) => { 
    // kick off some process 
}; 
YourQueue.DidEnqueue += (sender, e) => { 
    // kick off some process 
    // e.Item provides access to the enqueued item, if you like 
}; 
YourQueue.WillDequeue += (sender, e) => { 
    // kick off some process 
}; 
YourQueue.DidDequeue += (sender, e) => { 
    // kick off some process 
    // e.Item provides access to the dequeued item, if you like 
}; 

一个绝妙的技巧是,你可以使用DidDequeue方法揭开序幕一些过程,以保证队列已满通过使网络请求或从文件系统加载一些数据等。我在Xamarin移动应用程序中使用这个类来确保数据和图像被预先缓存以提供流畅的用户体验,而不是在滚动到屏幕后加载图像(如你可能会在Facebook和无数其他应用程序中看到)。

相关问题