加载程序时更改WPF标签内容

本文关键字:标签 WPF 程序 加载 | 更新日期: 2023-09-27 18:00:30

我有一个WPF应用程序,它在相同的代码块中加载了大量内容和UI更新,我想在Label.Content属性中显示进度或正在执行的任务,目前我正在执行以下操作:

void LoadEverything()
{
    UpdateContentLabel("Loading items");
    foreach(string i in stringArrayItems)
    {
         UpdateContentLabel("Loading " + i + " info...");
         //LoadTasks
    }
    UpdateContentLabel("Loading history");
}
void UpdateContentLabel(string Task)
{
    myLoadLabel.Content = Task;
}

第一个问题是标签内容没有更新,我知道UI线程和任务线程是相同的,这就是UI冻结的原因,我尝试使用BackgroundWorker将加载任务放在上面,this.Dispatcher.BeginInvoke((Action)delegate { /*UI Updates */ }); UI更新(比如创建自定义ListBoxItem并将其添加到ListBox),并在app.ShowDialog();中抛出TargetInvocationExceptionapp不是第一种形式,是mainApp对话框,在登录窗口中创建)。

BackgroundWorker loadInfo = new BackgroundWorker();
private void app_Loaded(object sender, RoutedEventArgs e)
{
    loadInfo.DoWork += loadInfo_DoWork;
    loadInfo.RunWorkerCompleted += loadInfo_RunWorkerCompleted;
    loadInfo.WorkerReportsProgress = true;
    loadInfo.RunWorkerAsync();
}
public void loadInfo_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    UpdateContentLabel("Load complete :)");
}
public void loadInfo_DoWork(object sender, DoWorkEventArgs e)
{
    this.Dispatcher.BeginInvoke((Action)delegate { UpdateContentLabel("Loading items"); });
    foreach(string i in stringArrayItems)
    {
         this.Dispatcher.BeginInvoke((Action)delegate { UpdateContentLabel("Loading " + i + " info..."); });
         //LoadTasks
         this.Dispatcher.BeginInvoke((Action)delegate { /*UI Updates */ });
    }
}

所以,问题是我该怎么做才能在前面提到的标签中显示当前任务?

编辑:NET的versión项目是3.5。

加载程序时更改WPF标签内容

将逻辑放入foreach循环中,而不是第二个BeginInvoke循环中。

下面是一个正在运行的功能示例:

public partial class MainWindow : Window
{
    BackgroundWorker loadInfo = new BackgroundWorker();
    private List<string> stringArrayItems = new List<string>{
        "First file",
        "second file",
        "third file ",
        "fourth file "
    };
    public MainWindow()
    {
        InitializeComponent();
        loadInfo.DoWork += loadInfo_DoWork;
        loadInfo.RunWorkerCompleted += loadInfo_RunWorkerCompleted;
        loadInfo.WorkerReportsProgress = true;
        loadInfo.RunWorkerAsync();
    }
    public void loadInfo_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        UpdateContentLabel("Load complete :)");
    }
    public void loadInfo_DoWork(object sender, DoWorkEventArgs e)
    {
        this.Dispatcher.BeginInvoke((Action)(() => UpdateContentLabel("Loading items")));
        foreach (string i in stringArrayItems)
        {
            this.Dispatcher.BeginInvoke((Action)(() =>
                UpdateContentLabel("Loading " + i + " info...")
            ));
            //LoadTasks
            Thread.Sleep(1000);
            Console.Out.WriteLine("Loading {0} and sleeping for a second.", i);
        }
    }
    void UpdateContentLabel(string Task)
    {
        MyLabel.Content = Task;
    }
}

在这里,我创建了与您的代码场景相匹配的示例代码。这里的想法不是直接从代码后面访问UI元素(在您的例子中是ListBox)。通过使用INotifyPropertyChanged,您可以利用List集合绑定到ListBox的ItemsSource,并在代码隐藏上更新绑定的集合,从而消除UI线程附件要求。所以你来了:

<Grid x:Name="MainGrid">
    <ListBox ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="MainListBox" ItemsSource="{Binding AvailableListItems}">
    </ListBox>
</Grid>

代码背后:

public partial class MainWindow : INotifyPropertyChanged
{
    #region INotifyPropertyChanged section
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
    private List<int> availableListItems;
    public List<int> AvailableListItems
    {
        get
        {
            return availableListItems;
        }
        set
        {
            availableListItems = value;
            OnPropertyChanged("AvailableListItems");
        }
    }
    public MainWindow()
    {
        InitializeComponent();
        AvailableListItems = new List<int>();
        this.DataContext = this;
    }
    BackgroundWorker loadInfo = new BackgroundWorker();
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        loadInfo.DoWork += loadInfo_DoWork;
        loadInfo.WorkerReportsProgress = true;
        loadInfo.RunWorkerAsync();
    }
    public void loadInfo_DoWork(object sender, DoWorkEventArgs e)
    {
        for(int i = 0; i < 2000; i++)
        {
            AvailableListItems.Add(i);
            Thread.Sleep(1);
            OnPropertyChanged("OnPropertyChanged");
        }
    }
}

希望这会有所帮助。