How to implement progress using IEnumerable?

2019-08-02 12:22发布

I have a method that loops through an IEnumerable collection and passes each of them to another method. Something like:

void Run (object item)
{
    foreach(var method in this.Methods)
        method (item);
)

How can I implement sort of progress that will be reflected in a progress bar? I could do this easily if it was directly coded inside this method but this method is contained in a type outside the ViewModel, which I can call of course.

I just don't know how to implement it and get it from that method and reflect the changes in the UI, by passing it to ViewModel, etc.

Any ideas?

2条回答
淡お忘
2楼-- · 2019-08-02 12:47

I would approach this by using events as follows.

public class ViewModel : ViewModelBase
{
    private int m_CurrentProgress;
    private int m_MethodCount;

    // Bind this to the progress bar
    public int CurrentProgress
    {
        get { return m_CurrentProgress; }
        set
        {
            m_CurrentProgress = value;
            OnPropertyChanged("CurrentProgress");
        }
    }

    // Bind this to the progress bar
    public int MethodCount
    {
        get { return m_MethodCount; }
        set
        {
            m_MethodCount = value;
            OnPropertyChanged("MethodCount");
        }
    }

    private void MethodExecuted(object sender, EventArgs e)
    {
        CurrentProgress++;
    }

    public void Run()
    {
        var c = new ExternalClass();
        MethodCount = c.Methods.Count;
        c.MethodExecuted += MethodExecuted;

        c.Run(null);
    }
}

public class ExternalClass
{
    public List<object> Methods { get; set; }

    public event EventHandler<EventArgs> MethodExecuted;

    public void InvokeMethodExecuted(EventArgs e)
    {
        EventHandler<EventArgs> handler = MethodExecuted;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    public void Run(object item)
    {
        foreach (var method in Methods)
        {
            method(item);

            InvokeMethodExecuted(null);
        }
    }
}
查看更多
Anthone
3楼-- · 2019-08-02 12:56

What I end up doing is passing in delegate used for reporting progress. This provides very nice decoupling. The delegate can be implemented as a lambda function that directly sets the progress on the form.

void Run (object item, Action<float> progress)
{ 
    int total = MethodCollection.Count; 
    int index = 0;
    foreach(var method in MethodCollection)
    {
        method (item);
        progress(index/(float)total);
    }
)

For long running tasks, I would do this on a separate thread using BackgroundWorker, which has built in hooks for progress reporting.

查看更多
登录 后发表回答