在没有UI锁定的情况下在MVVM中实现长时间运行的业务逻辑

时间:2018-02-28 14:50:30

标签: c# .net mvvm

我目前正在练习MVVM模式,并且我希望实现一个不会冻结我的业务层中长时间运行逻辑的UI。让我解释一下。

查看: 我目前有一个进度条,随着后端的操作进度继续进行填充。

            <ProgressBar x:Name="prgFeedback" Height="25" Margin="10,20,10,40" Value="{Binding ProgressValue}" />

视图模型: 目前,我已经实现了一个基本视图模型,其中包含三个绑定到UI的属性。

class MyViewModel: INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };

    private string _InputPath { get; set; }
    private string _OutputPath { get; set; }
    private double _ProgressValue { get; set; }


    public string InputPath
    {
        get { return _InputPath; }
        set
        {
            if (_InputPath != value)
            {
                _InputPath = value;
                PropertyChanged(this, new PropertyChangedEventArgs("InputPath")); 
            }
        }
    }

    public string OutputPath
    {
        get { return _OutputPath; }
        set
        {
            if (_OutputPath != value)
            {
                _OutputPath = value;
                PropertyChanged(this, new PropertyChangedEventArgs("OutputPath"));
            }
        }

    }

    public double ProgressValue
    {
        get { return _ProgressValue; }
        set
        {
            if (_ProgressValue != value)
            {
                _ProgressValue = value;
                PropertyChanged(this, new PropertyChangedEventArgs("ProgressValue"));
            }
        }
    }

    public ICommand Button_Command{get;set;}

    public MyModel()
    {

        modelobj = new MyModel();
    }


    public void Button_Run()
    {
        ProgressValue = 0;
        InputPath = modelobj.DialogGetInput();

        //Get output here 
        thing.ProgressChanged += new EventHandler<WorkerEventArgs>(OnProgressChanged);
        OutputPath = modelobj.FlowLogic();
    }

    private void OnProgressChanged(object sender, WorkerEventArgs e)
    {
        ProgressValue = e.Progress;
    }
}

在这里,我将Command移动到公共构造函数,以便我的应用程序将从应用程序启动时运行循环。但是现在它已经绑定了UI上的一个按钮。

MODEL:所以这里是模型的精简版本我希望这足以让你了解我计划执行的操作。

public class MyModel
{


    #region Properties
    public  string OutputPath
    { get
        {
            return _OutputPath;
        }
        set
        { if (_OutputPath != value)
            {
                _OutputPath = value;
            }
        }
    }
    private  string _OutputPath{ get;  set; }

    public  string InputPath
    {
         get
        {
            return _InputPath;
        }
        set
        {
            if (_InputPath != value)
            {
                _InputPath = value;
            }
        }
    }

    private string _InputPath { get; set; }
    #endregion

   public MyModel()
    {
    }

    #region Helpers

    public event EventHandler<WorkerEventArgs> ProgressChanged;

    private void NotifyProgress(double current, double max)
    {
        if (ProgressChanged != null)
        {
            double progress = (current/max)*100 ; 
            ProgressChanged(this, new WorkerEventArgs(progress));
        }
    }
    #endregion  
    #region Logic
    public string DialogGetInput()
    {
            //Logic to get a path for the File containing the ID's

            return path;
    }


    private string Generate_Date_Info(string ID)
    {
        string tolog = "";

                    //Logic to get date for each ID from Database.

        return tolog;
    }

    public string FlowLogic()
    {


        string tolog="";
                    int i = 0; // used to get the current index from the list of ID's
                     int k = 0; // used to get the total count of ID's from file.


                foreach(string ID in IDs)  //IDs will contain all the IDs read from the file
                    {
                        tolog +=Generate_runs(ID);
                        tolog +=Generate_ID_Change(ID);
                        tolog +=Generate_Date_Info(ID);
                    }

                    //Write 'tolog' to a file using StreamWriter
        NotifyProgress(int i,int k);
        return OutputPath;



    }

    private string Generate_ID_Change(string ID)
    {

        string tolog = "";
        tolog += Environment.NewLine;

            //Logic to retrive addidtional data from Database

        return tolog;
    }

    private string Generate_runs(string ID)
    {
     string tolog = "";
     tolog += Environment.NewLine;

            //Logic to retrive Data from Database
     return tolog;
    }
    #endregion
}

正如另一篇文章指出的那样,我使用了工作人员事件来通知我的用户界面下面的进展变化。

    public class WorkerEventArgs : EventArgs
{
    public double Progress { get; private set; }

    public WorkerEventArgs(double progress)
    {
        Progress = progress;
    }
}

当我在逐步调试模式下运行时,我可以看到我的模型调用事件,它触发ViewModel上的值更改,然后我看到调用PropertyChanged,但我没有看到我的UI更新它&#39 ;进度条。

在运行此特定应用程序时,如何让UI响应。

1 个答案:

答案 0 :(得分:0)

您应该在自己的线程中运行长时间运行的操作。类似的东西:

    public DoLongRunningOperation()
    {

        Task.Run(() =>
        {
            for (var i = 0; i < 100; i++)
            {

                // Do some really cpu intense stuff.. 

                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
                {
                    ProgressValue = i;
                }));
            }
        });
    }

通过致电调度员,您可以跳回到主踏板。