WPF,如何强制更新文本框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26429467/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:37:27  来源:igfitidea点击:

WPF, How do I force a textbox to update

c#wpf.net-3.5

提问by user2026382

I'm playing around with WPF. I am limited to the .Net framework 3.5. I want to update a text box with simple status text while I run some long method. No matter what I try, I cannot seem to get the text box to update until the long method has completed. I have tried threading / using the controls dispatcher etc. In the example below, I have reverted back to simply hiving off the long method to a thread but it still wont work. The TextStatus textbox never gets updated until after the long method (LoadDevices) has completed. Can someone tell me how to do this? Any help much appreciated.

我在玩 WPF。我仅限于 .Net 框架 3.5。我想在运行一些长方法时用简单的状态文本更新文本框。无论我尝试什么,在 long 方法完成之前,我似乎都无法更新文本框。我尝试过线程/使用控件调度程序等。在下面的示例中,我已经恢复到简单地将 long 方法分离到一个线程,但它仍然无法工作。在长方法 (LoadDevices) 完成之前,TextStatus 文本框永远不会更新。有人能告诉我怎么做吗?非常感谢任何帮助。

    private void UpdateButton_Click(object sender, RoutedEventArgs e)
    {
        UpdateStatus("Searching for devices, please wait . . .");
        var t = new Thread(LoadDevices);
        t.Start();            
    }

    private void UpdateStatus(string status)
    {
        TextStatus.AppendText(status);
        TextStatus.InvalidateVisual();
    }

回答by Mikko Viitala

I think you are not providing enough code to figure out the problem. Still, fact is that your UI is blocked.

我认为您没有提供足够的代码来解决问题。尽管如此,事实是您的用户界面被阻止了。

Try the following, maybe it helps you figure it out (not using Tasksince it's not available in .NET Framework 3.5). It tries to simulate your long running LoadDevices()method while keeping the UI responsive.

尝试以下操作,也许它可以帮助您弄清楚(不使用,Task因为它在 中不可用.NET Framework 3.5)。它尝试模拟您长时间运行的LoadDevices()方法,同时保持 UI 响应。

MainWindows.xaml

主窗口.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="120"
        Width="400">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <Button Click="UpdateButtonClick" Grid.Row="0">Update</Button>
        <TextBox Name="TextStatus" Text="" TextWrapping="Wrap" Grid.Row="1"></TextBox>
    </Grid>
</Window>

MainWindows.xaml.cs

主窗口.xaml.cs

using System;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void UpdateButtonClick(object sender, RoutedEventArgs e)
        {
            UpdateStatus("Searching for devices, please wait");
            var thread = new Thread(LoadDevices);
            thread.Start();
        }

        private void LoadDevices()
        {
            // Your long running "load devices" implementation goes here
            for (int i = 0; i < 15; i++)
            {
                Dispatcher.BeginInvoke((Action) (() => UpdateStatus(".")));
                Thread.Sleep(250);
            }
            Dispatcher.BeginInvoke((Action)(() => UpdateStatus(" done")));
        }

        private void UpdateStatus(string status)
        {
            TextStatus.AppendText(status);
        }
    }
}

enter image description here

在此处输入图片说明

But yeah, you should prefer MVVM, Data binding, Commands, etc. and try to avoid stuffing logic into codebehind.

但是,是的,您应该更喜欢 MVVM、数据绑定、命令等,并尽量避免将逻辑填充到代码隐藏中。

回答by lloyd christmas

Try using the Task library. You will need to download this for .NET 3.5 : http://www.microsoft.com/en-us/download/details.aspx?id=24940

尝试使用任务库。您需要为 .NET 3.5 下载这个:http: //www.microsoft.com/en-us/download/details.aspx?id=24940

Task task = new Task(new Action(LoadDevices));
task.Start();

There are several ways to do this: http://dotnetcodr.com/2014/01/01/5-ways-to-start-a-task-in-net-c/

有几种方法可以做到这一点:http: //dotnetcodr.com/2014/01/01/5-ways-to-start-a-task-in-net-c/

回答by Uberbot7147

If you haven't tried delegates, that may be what you are looking for although it seems you may of tried this already. Inside your LoadDevices thread method, you could delegate back to invoke UpdateStatus with whatever text you want while your long method is running.

如果您还没有尝试过委托,那可能就是您正在寻找的东西,尽管您似乎已经尝试过了。在您的 LoadDevices 线程方法中,您可以委托回调用 UpdateStatus 以在您的长方法运行时使用您想要的任何文本。

The other case I see with the wording of your question is something local to the method Update-status is trying to change the text by a call to it. However, it cannot for some reason.

我在您的问题的措辞中看到的另一种情况是方法 Update-status 试图通过调用它来更改文本的本地方法。但是,由于某种原因,它不能。

This may be compleatly irrelevant to WPF, but in Forms:

这可能与 WPF 完全无关,但在表单中:

I'm assuming you have your loading thread somewhere else. I don't see you calling a doWork() or equivalent method in the thread though. If you want to update the status as your loading thread loads devices you could do:

我假设你在其他地方有你的加载线程。不过,我没有看到您在线程中调用 doWork() 或等效方法。如果您想在加载线程加载设备时更新状态,您可以执行以下操作:

    private delegate void UpdateStatusDel(string text); //This at your declarations
    UpdateStatusHandler = new UpdateStatusDel(UpdateStatus); //To initialize the delegate to /       //point to your update textbox function
    //say you have  
    string updateText = "Loading 10% done";
    //Then, in your thread you could invoke
    [locationOfHandeler].Invoke(UpdateStatusHandler, new object[] { updateText });