2014-04-27 49 views
1

而變化WPF標籤的內容我有一個加載了大量的在同一個代碼塊的內容和用戶界面更新一個WPF應用程序,我想表明的進展還是什麼任務是做在Label.Content物業,目前我「M這樣做:程序加載

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不是第一種形式,是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的項目版本是3.5。

+0

您使用的是MVVM模式嗎?你正在使用的任何其他框架? – Noctis

+0

@Noctis不,我沒有使用MVVM或其他框架,我使用的.NET版本是3.5 – FukYouAll

回答

1

把你的邏輯放在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; 
    } 
} 
+0

但是我有一個疑問,在'// LoadTasks'有UI更新,如'lbItems.Items。 Add(i);'或'if(lbItems.Items.Count <= 0){lNoItems.Visibility = Visibility.Visible; }並拋出'InvalidOperationException',我可以在哪裏移動這些UI更新並在任務中保持同步。對不起,不包括在問題中。 – FukYouAll

+0

@SteelersMan **第一**:然後更新你的問題。 ** Second **:我將所有的UI事物都移到一個方法中,並在那裏使用'BeginInvoke'。沒有更多的細節很難說。 **第三種**:我不知道MVVM是否是一種選擇,但它給予你的綁定和靈活性,將使所有這些GUI更新變得更加容易(如果你永遠不會之前玩過)。 – Noctis

+0

我試圖讓閱讀這個問題的人最容易閱讀,特別是在代碼中,這就是爲什麼我不小心忽略了一些信息,在我的代碼中有很多混合的UI操作(例如visibility屬性,add listboxitems,load自定義控件),I/O和資源管理(字節數組,BitmapImage等),我嘗試將它們中的一部分分開,但沒有得到我預期的結果(遍地例外)。 – FukYouAll

0

在這裏,我已經創建示例代碼以符合你的代碼的情況。在這裏,idea不是直接從後面的代碼訪問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"); 
     } 
    } 
} 

希望,這將是有幫助的。

+0

他沒有使用MVVM,所以我懷疑綁定和INPC將是他想要與... ... – Noctis