2011-11-16 65 views
3

我認爲C#win表格在某些情況下沒有被重新繪製的問題在不同的地方被覆蓋了,但是,我沒有設法通過使用我發現的簡單片段來解決我的問題網頁。C#ListView不更新

我的問題:在窗體上我有一個listView,我把它與一個自定義數據持有者(2列,一個鍵和最後一個更新日期)聯繫起來。從不同的地方,我需要調用updateTime(key)方法,然後複製GUI中的更改。該模型得到改變,但我的listView從來沒有。

我有一個包含一個ListView看起來像一個形式:

partial class VolsPane : UserControl, IGUIPane 
{ 
    private ListView listView1; 
    private ListModel listModel1;  //ListModel is 100% homemade 
    ... 
    public VolsPane() 
    { 
     ... 
     listModel1.setList(listView1); 
    } 
} 

而對於我的ListView類控股的數據是這樣的:

class ListModel 
{ 
    private Dictionary<string, DateTime> Underlying; 
    private ListView list; 

    ... 

    public ListModel(string nexusKey) 
    { 
     ... 
    } 

    ... 

    public void setList(ListView list) 
    { 
     this.list = list; 
    } 


    public void updateTime(string ric) 
    { 
     Underlying[ric] = DateTime.UtcNow; 
     updateView(); 
    } 

    public void updateView() 
    { 
     this.list.Clear(); 
     this.list.Items.AddRange(this.underlyingToListItems()); 
    } 

    ... 

    public ListViewItem[] underlyingToListItems() 
    { 
     ListViewItem[] res = new ListViewItem[Underlying.Keys.Count]; 
     int i = 0; 
     foreach (string ric in Underlying.Keys) 
     { 
      res[i] = new ListViewItem(new string[] { ric, Underlying[ric].ToString("MMM-dd hh:mm:ss") }); 
      i++; 
     } 
     return res; 
    } 

} 

我意識到問題出在我的updateView()中。在調試中,代碼肯定會去那裏。相信這個問題是與異步「調用」來解決,我提到這個帖子這似乎是一個參考:Stack overflow : Automating the invoke...

然後嘗試這樣:

private void updateView() 
    { 
     if (this.list.InvokeRequired) 
     { 
      this.list.Invoke(new MethodInvoker(() => { updateView(); })); 
     } 
     else 
     { 
      this.list.Items.Clear(); 
      //this.list.Clear(); 
      this.list.Items.AddRange(this.underlyingToListItems()); 
     } 
    } 

它建立,但沒有效果。在調試模式下,永遠不會進入'if'分支,總是'else'。

那麼這個:

private void updateView() 
    { 
     this.list.Invoke((MethodInvoker)delegate 
     { 
      this.list.Items.Clear(); 
      //this.list.Clear(); 
      this.list.Items.AddRange(this.underlyingToListItems()); 
     }); 
    } 

我得到一個「:調用或BeginInvoke可直到窗口句柄已創建不能在一個控件調用InvalidOperationException異常。」

我必須在這裏失蹤的顯而易見的事情是什麼?或者,我的問題實際上不是我認爲的問題?

謝謝你們!

回答

3

你是對的,問題在於updateView()代碼。你確實需要調用UI線程,但問題是尚未爲控件創建句柄。使用WinForms時遇到的一個問題是,如果尚未創建句柄,則InvokeRequired實際上將返回false。請參閱此說明表MSDN documentation

如果控件的句柄尚不存在,則InvokeRequired會搜索控件的父鏈,直到找到具有窗口句柄的控件或表單。如果找不到合適的句柄,InvokeRequired方法將返回false

這就是爲什麼您對InvokeRequired的檢查總是失敗。我已經看到這個問題在幾個方面解決。一個解決方案是一個回調附加到控件的句柄創建的事件:

public class HandleHookedListView: ListView 
{ 
    private EventHandler _handleCreatedEvent; 

    public HandleHookedListView(): base() 
    { 
     _handleCreatedEvent = new EventHandler(HandleHookedControl_HandleCreated); 
     this.HandleCreated += _handleCreatedEvent; 
    } 

    private bool _handleIsCreated; 

    public bool HandleIsCreated 
    { 
     get { return _handleIsCreated; } 
     set { _handleIsCreated = value; } 
    } 

    void HandleHookedControl_HandleCreated(object sender, EventArgs e) 
    { 
     Debug.Print("Handle Created"); 
     this.HandleIsCreated = true; 

     // Unhook the delegate 
     if (_handleCreatedEvent != null) 
      this.HandleCreated -= _handleCreatedEvent; 
    } 
} 

這樣您就可以修改您的UpdateView檢查手柄已創建。在這種情況下,你的ListView(列表)的實例已經被替換爲新HandleHookedListView

private void updateView() 
{ 
    var handleCreated = this.list.HandleIsCreated; 
    if (this.list.InvokeRequired && handleCreated) 
    { 
     // Handle is created and invoke is required. 
     this.list.Invoke(new MethodInvoker(() => { updateView(); })); 
    } 
    else if (handleCreated) 
    { 
     // In this case your control's handle has been created and invoke really 
     // isn't required go ahead and do the update 

     this.list.Items.Clear(); 
     this.list.Items.AddRange(this.underlyingToListItems()); 
    } 
    else 
    { 
     // You cannot update yet. The handle has not been created. Depending on if 
     // you need to "queue" these updates you can either collect them or just 
     // ignore them if a subsequent call to updateView() after the handle has been 
     // created will be sufficient 
    } 
} 

這裏真正的關鍵是,你正在嘗試做一個更新控制已經完全初始化之前。

1

首先

不建,調用我的列表模式不存在。

據我記得,Invoke是Control類的方法。 因此,如果沒有從Control繼承的任何類實例,就無法在ListModel類中調用它。 使用

this.list.Invoke( 

在調試模式,永不熄滅的「如果」分支,永遠是「其他」。

這可能意味着this.list.InvokeRequired在GUI thead中被調用。

它也可能意味着list.InvokeRequired被稱爲之前this.list被漆成至少一次。 這是棘手的時刻。如果Control類的實例還沒有繪製成gdi +(或者C#WinForm繪畫的底層)尚未初始化。所以沒有什麼可以同步。 請仔細檢查。

+0

嗯,對我不是很清楚,對不起 – Jerome

+0

做了更改,但我仍然得到一個異常 – Jerome

+0

@jerome G:Again:「InvalidOperationException:Invoke或BeginInvoke不能在控件上調用,直到窗口句柄被創建。 「 這意味着控制尚未創建。我不能提供任何建議 這是問題的根源。 – VMykyt