wpf 文本框内容在加载时冻结 ui

wpf textbox content freezes ui on load

我开始编写我的第一个 WPF 应用程序,但我在使用显示一些系统信息(cpu、内存、磁盘使用情况、mac 地址等)的文本框时遇到了问题。 我的应用程序在两个页面之间进行导航,并且所述文本框位于其中一个页面上。文本框的内容通过 WMI 查询检索。 我注意到的问题是,在使用文本框导航到该页面时,它会冻结 UI 大约两秒钟,然后再转到并显示该页面。 我是新手,我最好的猜测是八个 WMI 查询(也可能编码错误)正在这样做,或者我错误地将内容加载到文本框中。 我的查询是如何构建的示例

public string getCPU()
    {
        ManagementObjectSearcher searcher = new
        ManagementObjectSearcher("root\CIMV2", "SELECT * FROM Win32_Processor");
        StringBuilder sb = new StringBuilder();
        foreach (ManagementObject wmi in searcher.Get())
        {
            try
            {
                sb.Append("Processor: " + wmi.GetPropertyValue("Name").ToString() + Environment.NewLine);
            }
            catch
            {
                return sb.ToString();
            }
        }
        return sb.ToString();
    }
    public string getRAMsize()
    {
        ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
        ManagementObjectCollection moc = mc.GetInstances();
        foreach (ManagementObject item in moc)
        {
            return Convert.ToString(Math.Round(Convert.ToDouble(item.Properties["TotalPhysicalMemory"].Value) / (1024 * 1024 * 1024), 0)) + " GB";
        }

        return "RAMsize";
    }

这就是我用来检索文本框中数据的方法:

private void TextBox1_Loaded(object sender, RoutedEventArgs e)
    {
        TextBox1.Text = getCPU();
        TextBox1.Text += "Memory:  " + getRAMsize() + Environment.NewLine;
        TextBox1.Text += "Free Space:  " + GetTotalFreeSpace(sysdrive) + " GB" + Environment.NewLine;
        if (Is64BitSystem)
        {
            TextBox1.Text += getOS() + " 64bit" + Environment.NewLine;
        }
        else
        {
            TextBox1.Text += getOS() + " 32 Bit" + Environment.NewLine;
        }
        TextBox1.Text += "MAC Address : " + System.Text.RegularExpressions.Regex.Replace(GetMacAddress().ToString(), ".{2}", "[=12=] ") + Environment.NewLine;
        TextBox1.Text += av();
    }

我的问题是我做错了什么,我该如何解决。在我看来,如果查询构造正确,那是因为每次加载文本框时(在导航或启动时)它们都会一次又一次地完成,也许如果我能让它只加载一次并记住这些值(因为大多数数据应该保持不变)。 但正如我所说,我是菜鸟,我们将不胜感激任何帮助。 提前致谢

您正在 UI 话题中获取数据。

您应该在后台线程中加载数据,然后,因为您使用 wpf,所以将文本框文本绑定到一个变量。

示例(此代码已准备好复制粘贴):

// INotifyPropertyChanged is an Interface which enables binding of Properties in your window
public partial class MainWindow : Window, INotifyPropertyChanged
{
    private string _systemInformation;

    // Stub (works actually)
    private bool is64BitSystem = (IntPtr.Size == 8);

    // Stub
    private string sysdrive = "YOLO\:";

    public MainWindow()
    {
        InitializeComponent();
        // Set Datacontext normally set to a viewmodel but ther is none in this code
        this.DataContext = this;

        // The Backgroundworker does things in the background (nonblocking)
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += DoItButDontInterruptMeDuh;
        bw.RunWorkerAsync();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public string SystemInformation { get => _systemInformation; set => _systemInformation = value; }

    //Stub
    public string getCPU()
    {
        return "Fancy CPU";
    }

    //Stub
    public string getRAMsize()
    {
        return "1 PB";
    }

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    //Stub
    private string av()
    {
        return "Whatever av means.";
    }

    private void DoItButDontInterruptMeDuh(object sender, DoWorkEventArgs e)
    {
        // Simulate loading time
        Thread.Sleep(5000);

        SystemInformation = getCPU();
        SystemInformation += "Memory:  " + getRAMsize() + Environment.NewLine;
        SystemInformation += "Free Space:  " + GetTotalFreeSpace(sysdrive) + " GB" + Environment.NewLine;
        if (is64BitSystem)
        {
            SystemInformation += getOS() + " 64bit" + Environment.NewLine;
        }
        else
        {
            SystemInformation += getOS() + " 32 Bit" + Environment.NewLine;
        }
        SystemInformation += "MAC Address : " + System.Text.RegularExpressions.Regex.Replace(GetMacAddress().ToString(), ".{2}", "[=10=] ") + Environment.NewLine;
        SystemInformation += av();
        OnPropertyChanged("SystemInformation");
    }

    //Stub
    private object GetMacAddress()
    {
        return "Macintoshstreet 1234";
    }

    //Stub
    private string getOS()
    {
        return "Cool OS";
    }

    //Stub
    private string GetTotalFreeSpace(object sysdrive)
    {
        return "0";
    }
}

并在 .xaml:

<TextBox Text={Binding Path=SystemInformation}/>

在检查了每一个查询之后,我发现 getCPU 导致加载延迟。 我用 Registry.GetValue 替换了它,速度非常快。 感谢 Sebastian L,因为虽然他的代码对我不起作用,但它让我走上了正确的道路,而且我能够使用后台工作者调整自己的代码以避免 UI 任何形式的冻结 我的工作代码:

private void TextBox1_Loaded(object sender, RoutedEventArgs e)
    {

        BackgroundWorker bw = new BackgroundWorker();
        bw.WorkerReportsProgress = true;
        bw.DoWork += new DoWorkEventHandler(delegate (object o, DoWorkEventArgs args)
        {

        });
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate (object o, RunWorkerCompletedEventArgs args)
        {
            TextBox1.Text = (string)Registry.GetValue(@"HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor[=10=]", "ProcessorNameString", null) + Environment.NewLine;
            TextBox1.Text += "Memory:  " + getRAMsize() + Environment.NewLine;
            TextBox1.Text += "Free Space:  " + GetTotalFreeSpace(sysdrive) + " GB" + Environment.NewLine;
            if (Is64BitSystem)
            {
                TextBox1.Text += getOS() + " 64bit" + Environment.NewLine;
            }
            else
            {
                TextBox1.Text += getOS() + " 32 Bit" + Environment.NewLine;
            }
            TextBox1.Text += "MAC Address : " + System.Text.RegularExpressions.Regex.Replace(GetMacAddress().ToString(), ".{2}", "[=10=] ") + Environment.NewLine;
            TextBox1.Text += av();
        });
        bw.RunWorkerAsync();
    }