按第二类更改文本

本文关键字:二类 文本 | 更新日期: 2023-09-27 18:11:29

我现在正在学习c#。

我的问题是:

我有2类。MainWindow.xaml.cs用于UI,另一个称为dosomething.cs

如果点击UI上的一个按钮,应该调用dosomething.cs中的一个方法。这很好。我希望dosomething.cs在运行点击处理程序(需要一些时间)时告诉UI的实际状态。

status_textblock = "test";
for (int i = 1; i<1000000; i++)
i += i;
Thread.sleep(100);
Status_textblock = i.tostring();
}

我该怎么做才能让每个新值立即出现在UI中?我已经尝试了BackgroundworkerDispatcher,但没有成功。

按第二类更改文本

我会使用BackgroundWorker here。在dosomething.cs的函数中,您启动worker,并且您的UI-CodeBehind订阅dosomething事件。

小例子:

UI-Codebehind:

private void ButtonClick(object sender, ...)
{
   var doSomething = new DoSomething();
   doSomething.StatusChanged += OnStatusChanged;
   doSomething.Do();
}
private void OnStatusChagned(string state)
{ 
   // Update the UI with the state 
}
是的,

public class DoSomething
        {
            public void Do()
            {
                var worker = new BackgroundWorker();
                worker.WorkerReportsProgress = true;
                worker.DoWork += WorkerOnDoWork;
                worker.ProgressChanged += WorkerOnProgressChanged;
                worker.RunWorkerAsync("Paremeter to pass to the BackgroundWorker");
            }
            private void WorkerOnProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                var temp = StatusChanged;
                if (temp != null)
                    temp((string) e.UserState);
            }
            private void WorkerOnDoWork(object sender, DoWorkEventArgs e)
            {
                var worker = (BackgroundWorker) sender;
                // If you want to get the passed argument you can call
                var parameter = e.Argument;
                for (int i = 0; i < 100000; i++)
                {
                    // do your background-stuff here
                    // ...
                    // Notify the UI
                    worker.ReportProgress(0, "STATUS-OBJECT");
                }
            }
            public delegate void OnStatusChanged(string status);
            public event OnStatusChanged StatusChanged;
        }

问题1:参考MainWindow.cs:

在面向对象编程中,你解耦组件以获得更好的概述、可测试性继承等。但是你必须考虑如何在对象之间传播引用。我的意思是:类dosomething的实例必须有一个对主窗口的引用,以便能够更新它的任何东西。你现在要做的是:在方法中创建一个MainWindow的新实例,并改变其状态(但不是实际可视化的MainWindow)

您可以将对实际MainWindow的引用传递给函数。这叫做依赖注入。通常情况下,你只注入一个由MainWindow类实现的接口,所以另一个类也可以使用这个功能,但这有点过头了。快速修复:

public void Do(MainWindow window)
{
    window.status_textblock = "test";
    for (int i = 1; i<1000000; i++)
    i += i;
    Thread.sleep(100);
    window.status_textblock = i.tostring();
}

并在主窗口中调用它:

new Dosomething().Do(this);

但是这仍然不起作用,因为线程被阻塞(使用Thread. sleep),并且只会在线程空闲时显示结果。

问题2:您必须在另一个线程/任务

中运行它
public void Do(MainWindow window)
{
    Task.Factory.StartNew(() => {
        window.status_textblock = "test";
        for (int i = 1; i < 1000000; i++)
            i += i;
        Thread.sleep(100);
        window.status_textblock = i.tostring();
    });
}

但是等一下,这也不会工作,因为你试图从另一个线程更新UI,这是不允许的

问题3:使用STA线程更新UI

在MainWindow类中,你创建了一个方法来更新STA线程上的状态文本(STA线程是唯一允许更新UI上任何东西的线程)。

public void UpdateStatus(string status)
{
    if (this.Dispatcher.CheckAccess())
        this.status_textblock = status;
    else
        this.Dispatcher.Invoke(new Action<string>(UpdateStatus), status);
}

在DoSomething类中调用UpdateStatus方法:

public void Do(MainWindow window)
{
    Task.Factory.StartNew(() => {
        window.UpdateStatus("test");
        for (int i = 1; i < 1000000; i++)
            i += i;
        Thread.sleep(100);
        window.UpdateStatus(i.tostring());
    });
}

->它工作!

在更多关于这个主题的文章中推荐使用Backgroundworker。你要做的是:

  1. 当按钮被点击时启动一个新的Backgroundworker

  2. 绑定DoWorkProgressChanged事件

  3. 在DoWork委托中,您可以使用自定义对象或单个整数调用ReportProgress

  4. 绑定到ProgressChanged的方法将在UI线程上触发,在那里你可以更新标签或任何你喜欢的东西。

  5. 也许你应该"refresh"这篇文章的答案的页面/视图。

    有关Backgroundworker的更多信息,请查看此处。