private void OnElementFinished(object o, EventArgs args)
        {
            bool any_processing = false;

            lock (sync) {
                QueuePipelineElement <T> element = FirstElement;
                while (element != null)
                {
                    any_processing |= element.Processing || element.ProcessedCount < element.TotalCount;
                    if (any_processing)
                    {
                        break;
                    }
                    element = element.NextElement;
                }
            }

            if (!any_processing)
            {
                OnFinished();
            }
        }
        public void AddElement(QueuePipelineElement <T> element)
        {
            element.Finished += OnElementFinished;
            lock (sync) {
                if (first_element == null)
                {
                    first_element = element;
                    return;
                }

                QueuePipelineElement <T> current = first_element;

                while (current != null)
                {
                    if (current.NextElement == null)
                    {
                        current.NextElement = element;
                        break;
                    }

                    current = current.NextElement;
                }
            }
        }