与前台xaml同时运行backgroundtask

时间:2018-02-01 13:13:01

标签: c# xaml background raspberry-pi

我正在尝试将后台应用程序集成到需要同时运行的前台应用程序中                                                                                   我一直在阅读许多Microsoft文档,似乎我无法理解它们的含义。我是XAML的初学者。这应该是覆盆子pi,背景代码用于传感器,而前景应该有按钮,用户可以点击OTP,如果他们没有RFID.OTP我可以管理,但我是有问题将背景整合到XAML中                                                                                 我对此过分强调。请帮帮我

更新:

我明天会在Pi上尝试你的建议,希望它会起作用:)

         private void OnPageLoaded(object sender, RoutedEventArgs e)
      {

        int interval = 20;
        DateTime dueTime = DateTime.Now.AddMilliseconds(interval);

        while (true)
        {
            if (DateTime.Now >= dueTime)
            {
                //insert code here
                initComms();
                StartUart();

                //self monitoring 
                startLightMonitoring();

                //Initial State
                CurMode = Neutral;
                Debug.WriteLine("===Entering MODE_SENDLIGHT===");

                // This make sure the main program run idefinitely 
                while (true)
                {
                    Sleep(300);

                    //state machine
                    handleModeSendLight();

                    if (CurMode == Neutral)
                    {
                        MailBoxMonitoring();
                    }
                    else if (CurMode == AccessMode)
                    {
                        AccessGranted();
                    }
                    else if (CurMode == IntrusionMode)
                    {
                        InvalidAccess();
                    }
                    else
                    {
                        Debug.WriteLine("Config Error");
                    }
                    //Update next dueTime
                    dueTime = DateTime.Now.AddMilliseconds(interval);
                }


            }
            else
            {
                //Just yield to not tax out the CPU
                Sleep(1);
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

<强> MVVM:

您正在使用XAML和UWP。这意味着您应该使用MVVM模式。虽然您可以使用其他方法,但XAML和WPF / UWP在设计时考虑了MVVM。你失去了大约90%的XAML功能,并且由于不使用MVVM而遇到了大量的附加问题。几年前我写了一篇介绍: https://social.msdn.microsoft.com/Forums/vstudio/en-US/b1a8bf14-4acd-4d77-9df8-bdb95b02dbe2/lets-talk-about-mvvm?forum=wpf

后台操作:

在.NET中进行多任务/ - 线程的方法有很多种。 BackgroundWorker,Async ...等待,任务,线程化你在上面的评论中链接的内容。对于初学者,我会建议后台工作者,我为此编写了一个示例代码。但你的情况并不是初学者的水平:

&#13;
&#13;
#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
	if (!bgwPrim.IsBusy)
	{
		//Prepare ProgressBar and Textbox
		int temp = (int)nudPrim.Value;
		pgbPrim.Maximum = temp;
		tbPrim.Text = "";

		//Start processing
		bgwPrim.RunWorkerAsync(temp);
	}
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
	if (bgwPrim.IsBusy)
	{
		bgwPrim.CancelAsync();
	}
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
	int highestToCheck = (int)e.Argument;
	//Get a reference to the BackgroundWorker running this code
	//for Progress Updates and Cancelation checking
	BackgroundWorker thisWorker = (BackgroundWorker)sender;

	//Create the list that stores the results and is returned by DoWork
	List<int> Primes = new List<int>();
	

	//Check all uneven numbers between 1 and whatever the user choose as upper limit
	for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
	{
		//Report progress
		thisWorker.ReportProgress(PrimeCandidate);
		bool isNoPrime = false;

		//Check if the Cancelation was requested during the last loop
		if (thisWorker.CancellationPending)
		{
			//Tell the Backgroundworker you are canceling and exit the for-loop
			e.Cancel = true;
			break;
		}

		//Determin if this is a Prime Number
		for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
		{
			if (PrimeCandidate % j == 0)
				isNoPrime = true;
		}

		if (!isNoPrime)
			Primes.Add(PrimeCandidate);
	}

	//Tell the progress bar you are finished
	thisWorker.ReportProgress(highestToCheck);

	//Save Return Value
	e.Result = Primes.ToArray();
}

private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
	pgbPrim.Value = e.ProgressPercentage;
}

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
	pgbPrim.Value = pgbPrim.Maximum;
	this.Refresh();

	if (!e.Cancelled && e.Error == null)
	{
		//Show the Result
		int[] Primes = (int[])e.Result;

		StringBuilder sbOutput = new StringBuilder();

		foreach (int Prim in Primes)
		{
			sbOutput.Append(Prim.ToString() + Environment.NewLine);
		}

		tbPrim.Text = sbOutput.ToString();
	}
	else 
	{
		tbPrim.Text = "Operation canceled by user or Exception";
	}
}
#endregion
&#13;
&#13;
&#13; 您可以使用进度报告将当前传感器数据传递出线程。将它们公开在ViewModel上的Property中。

GUI写入开销:

您的案例很棘手,因为您需要一个几乎永久运行的线程,并且大部分工作都是通过Progress Reporting完成的。问题在于编写GUI非常昂贵。如果每个用户启动事件只执行一次,那么这并不重要,但是在这里你有一个循环(在另一个线程或任务中)重复写入(通过更改通知或直接)。您可以通过太多更改完全重载GUI线程。事实上,我上面代码的原始变体就是这样:我试图通过Progress报告分发每个找到的素数,然后将它附加到输出框。在一个足够大的上限,它发现了如此多的素数如此之快,将它们附加到输出框的字符串完全对GUI线程征税了一段时间。由于素数变得罕见,GUI线程设法赶上。但是,您的数据收集将始终以相同的速度运行。我也为这个问题写了一个例子:

&#13;
&#13;
using System;
using System.Windows.Forms;

namespace UIWriteOverhead
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        int[] getNumbers(int upperLimit)
        {
            int[] ReturnValue = new int[upperLimit];

            for (int i = 0; i < ReturnValue.Length; i++)
                ReturnValue[i] = i;

            return ReturnValue;
        }

        void printWithBuffer(int[] Values)
        {
            textBox1.Text = "";
            string buffer = "";

            foreach (int Number in Values)
                buffer += Number.ToString() + Environment.NewLine;
            textBox1.Text = buffer;
        }

        void printDirectly(int[] Values){
            textBox1.Text = "";

            foreach (int Number in Values)
                textBox1.Text += Number.ToString() + Environment.NewLine;
        }

        private void btnPrintBuffer_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Generating Numbers");
            int[] temp = getNumbers(10000);
            MessageBox.Show("Printing with buffer");
            printWithBuffer(temp);
            MessageBox.Show("Printing done");
        }

        private void btnPrintDirect_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Generating Numbers");
            int[] temp = getNumbers(1000);
            MessageBox.Show("Printing directly");
            printDirectly(temp);
            MessageBox.Show("Printing done");
        }
    }
}
&#13;
&#13;
&#13;

有两种解决方法:

  1. 请勿使用更改通知。您仍然可以在ViewModel端使用为其配置的属性,但不要让View注册它。而是让视图通过Timer轮询值。这样,您就可以将GUI的更改保持在可管理的水平。
  2. 限制收集新数据的频率。您可以应用简单的速率限制,因此不会经常获取(和报告)新数据:
    &#13;
    &#13;
    integer interval = 20;
    DateTime dueTime = DateTime.Now.AddMillisconds(interval);
    
    while(true){
      if(DateTime.Now >= dueTime){
        //insert code here
    
    	//Update next dueTime
    	dueTime = DateTime.Now.AddMillisconds(interval);
      }
      else{
        //Just yield to not tax out the CPU
        Thread.Sleep(1);
      }
    }
    &#13;
    &#13;
    &#13; 请注意,这只是一个上限。如果数据收集每个itteartion需要20毫秒,则此代码将无法更快地运行。此外,DateTime.Now使用的Windows时钟几乎不是accurate as the Type allows Precision。在测试中,我有5-18毫秒的延迟,这些值不断变化。