【发布时间】:2019-09-30 02:54:02
【问题描述】:
我已经以这种方式实现了自己的 ObservableQueue:
public class ObservableQueue<T> : Queue<T>, INotifyPropertyChanged, INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableQueue() : base() { }
public ObservableQueue(IEnumerable<T> collection) : base(collection) { }
public ObservableQueue(int capacity) : base(capacity) { }
public virtual new T Enqueue(T item)
{
lock (this)
{
base.Enqueue(item);
}
OnCollectionChanged(NotifyCollectionChangedAction.Add, item);
return item;
}
public virtual new T Dequeue()
{
lock (this)
{
var item = base.Dequeue();
return item;
}
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, T item)
{
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(
action
, item
, item == null ? -1 : 0)
);
OnPropertyChanged(nameof(Count));
}
protected virtual void OnPropertyChanged(string proertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(proertyName));
}
}
我订阅了 MainWindow 中的队列:
paths.CollectionChanged += Process;
当一个文件被添加到一个特定的文件夹时,我排队:
private void FileCreated(Object sender, FileSystemEventArgs e)
{
try
{
paths.Enqueue(currentPath);
} catch (InvalidOperationException exception)
{
string messageBoxText = exception.Message;
MessageBoxButton button = MessageBoxButton.OK;
System.Windows.MessageBox.Show(messageBoxText, "Error", button);
}
}
这会触发队列上的 CollectionChanged,我在其中运行它:
private async void Process(object sender, NotifyCollectionChangedEventArgs e)
{
var currentPath = paths.Dequeue();
await UploadFile(currentPath);
Thread.Sleep(5000);
try
{
MoveFile(currentPath, outputFolderPath, System.IO.Path.GetFileName(currentPath));
} catch (IOException IOE)
{
Console.WriteLine(IOE.StackTrace);
}
}
但我在尝试出队时收到以下错误:
System.InvalidOperationException: '队列为空。'
我似乎无法弄清楚队列怎么可能是空的?
我偶尔也会遇到以下异常:
异常信息:System.InvalidOperationException 在 System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource) 在 System.Collections.Generic.Queue
1[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].Dequeue() at Program.Utilities.ObservableQueue1[[System.__Canon,mscorlib, 版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089]].Dequeue() 在 Program.MainWindow+d__11.MoveNext() 在 System.Runtime.CompilerServices.AsyncMethodBuilderCore+c.b__6_1(System.Object) 在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object) 在 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback,System.Object,布尔值)在 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback,System.Object,布尔值)在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
【问题讨论】:
-
会不会是事件处理器被注册了多次?只有第一个调用才能出队。
-
如果没有可靠地重现问题的良好minimal reproducible example,就不可能提供好的答案。也就是说:恕我直言,您应该通过继承
ObservableCollection<T>而不是Queue<T>来实现您的ObservableQueue<T>。在现有的可观察集合类型上实现队列语义比在现有队列类型上实现集合更改语义要容易得多。 -
我尝试添加更多代码,但遇到了一个新异常。