2012-04-21 56 views
1

我試圖在WPF ListVieuw中顯示警報列表。爲了做到這一點,我將Listbox數據綁定到了一個包含警報列表的屬性。由於我使用了MVC編程範例,因此該屬性位於控制器中,並且視圖的datacontext被設置爲該控制器。在MVC應用程序中結合ObservableCollection <T>和列表<T>

我注意到,當我向列表中添加一個鬧鐘時,視圖沒有顯示新的鬧鐘。經過一番研究,我發現我需要使用ObservableCollection類來正確地做到這一點。

但是,顯示警報列表不是唯一需要完成的事情,所以我不能/不想將列表的變量類型更改爲ObservableCollection。

我現在試着做一個ObservableCollection類型的屬性,但這也不起作用。這很正常,因爲我沒有將警報添加到屬性中,所以我將它添加到仍然是List類型的變量中。

有沒有辦法在更新列表時告訴屬性,還是其他/更好的方式來顯示我的警報,並保持它們易於用於程序的其他部分?

編輯:

我的解決方法:我觸發PropertyChanged事件在從我的報警變量PropertyChanged事件的事件處理程序清除我的財產FutureEvents。

我的代碼: 類CMAIN { 私有靜態揮發CMAIN實例; private static object syncRoot = new Object();

ObservableCollection<Alarm> alarms; 

    #region properties 
    /// <summary> 
    /// Returns the list of alarms in the model. Can't be used to add alarms, use the AddAlarm method 
    /// </summary> 
    public ObservableCollection<Alarm> Alarms 
    { 
     get 
     { 
      return alarms; 
     } 
    } 

    /// <summary> 
    /// Returns the ObservableCollection of future alarms in the model to be displayed by the vieuw. 
    /// </summary> 
    public ObservableCollection<Alarm> FutureAlarms 
    { 
     get 
     { 
      //Only show alarms in the future and alarm that recure in the future 
      var fAlarms = new ObservableCollection<Alarm>(alarms.Where(a => a.DateTime > DateTime.Now || (a.EndRecurrency != null && a.EndRecurrency > DateTime.Now))); 
      return fAlarms; 
     } 
    } 

    /// <summary> 
    /// Returns a desctription of the date and time of the next alarm 
    /// </summary> 
    public String NextAlarmDescription 
    { 
     get 
     { 
      if (alarms != null) 
      { 
       return alarms.Last().DateTimeDescription; 
      } 
      else 
      { 
       return null; 
      } 
     } 
    } 
    #endregion //properties 


    #region public 

    /// <summary> 
    /// Returns the instance of the singleton 
    /// </summary> 
    public static cMain Instance 
    { 
     get 
     { 
      if (instance == null) //Check if an instance has been made before 
      { 
       lock (syncRoot) //Lock the ability to create instances, so this thread is the only thread that can excecute a constructor 
       { 
        if (instance == null) //Check if another thread initialized while we locked the object class 
         instance = new cMain(); 
       } 
      } 
      return instance; 
     } 
    } 

    /// <summary> 
    /// Shows a new intance of the new alarm window 
    /// </summary> 
    public void NewAlarmWindow() 
    { 
     vNewAlarm newAlarm = new vNewAlarm(); 
     newAlarm.Show(); 
    } 

    public void AddAlarm(Alarm alarm) 
    { 
     alarms.Add(alarm);    
    } 

    public void RemoveAlarm(Alarm alarm) 
    { 
     alarms.Remove(alarm); 
    } 

    public void StoreAlarms() 
    { 
     mXML.StoreAlarms(new List<Alarm>(alarms)); 
    } 

    #endregion //public 

    #region private 

    //Constructor is private because cMain is a singleton 
    private cMain() 
    { 
     alarms = new ObservableCollection<Alarm>(mXML.GetAlarms()); 
     alarms.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(alarms_CollectionChanged); 
    } 

    private void alarms_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     FutureAlarms.Clear(); //Needed to trigger the CollectionChanged event of FutureAlarms 
     StoreAlarms(); 
    } 


    #endregion //private 
} 

回答

0

WPF的PropertyChanged事件INotifyPropertyChanged界面的反應,所以你應該實現這個接口,當你在你的模型更改屬性引發事件。 如果你這樣做,你根本不需要使用ObservableCollection<T>。但請注意,如果您的財產是List並且您所做的唯一事情是添加或移除項目,WPF仍然會認爲它是相同的列表並且什麼也不做。因此,提高PropertyChanged事件之前,你需要屬性設置你一個列表的新實例,這是很容易這樣做:

MyList.add(newItem); 
MyList = new List<something>(MyList); 
#raise the event 
+0

一個列表沒有實現INotifyPropertyChanged,所以如何提高PropertyChanged事件? – Bitbored 2012-04-21 20:15:11

+0

@Bitbored,你的**控制器**應該實現它。 – 2012-04-21 20:24:39

0

而是在每次獲得與未來警報重新創建的ObservableCollection的,嘗試直接更新採集當列表改變:

public ObservableCollection<Alarm> FutureAlarms { get; private set;} // initialize in constructor 

private void UpdateFutureAlarms() { 
    fAlarms.Clear(); 
    fAlarms.AddRange(
     alarms.Where(
      a => a.DateTime > DateTime.Now 
       || (a.EndRecurrency != null && a.EndRecurrency > DateTime.Now) 
     ) 
    ) 
} 

//... somewhere else in the code... 

public void Foo() { 
    // change the list 
    alarms.Add(someAlarm); 
    UpdateFutureAlarms(); 
} 

你也可以註冊UpdateFutureAlarms作爲一個事件處理程序,如果你有一個事件觸發的List變化時。

0

你最好從ObservableCollection<T>中派生出你自己的類,並使用它來代替嘗試像你一樣封裝兩個現有類。至於爲什麼:

  • 第一,這將是更痛苦的,因爲ObservableCollection<T>已經實現了List<T>支持的所有接口,所以你只需要實現你確實需要直接從List<T>的方法和WPF數據綁定將只是工作;
  • 第二,唯一現實的其他選擇,INotifyPropertyChanged方法實施起來很麻煩(您將有效地重寫ObservableCollection<T>),否則如果您在每次更改後用新的替換它們以獲得較大的集合,將會導致較差的性能綁定更新。
+0

問題在於視圖只是程序的一小部分。還有很多其他類和很多代碼,全部使用List 來處理警報。如果我將主控制器中的列表類更改爲ObservableCollection,最好的情況是我只失去一致性,最糟糕的情況是我需要更改很多代碼才能使其正常工作。 – Bitbored 2012-04-21 20:30:43

+0

我也不確定是否將類型更改爲ObservableCollection可以工作,因爲我將警報添加到控制器的警報變量,但是我將listview綁定到屬性FutureAlarms,該屬性將處理結果,並且不會引發新的PropertyChanged事件。 – Bitbored 2012-04-21 20:36:20

+0

我明白了。但是,您的數據綁定困境不會消失,所以您可以嘗試以下內容。直接使用List ,可以設置類別別名(例如「使用AlarmList = List ;」)或從List 中派生名爲AlarmList的類,並全面更新所有舊列表引用。然後開始嘗試使用一個新的AlarmList:ObservableCollection 類,知道返回列表只有幾個字符。正如我所說,如果你想無障礙的數據綁定,(派生自)ObservableCollection 是最好的選擇。 – Alan 2012-04-21 20:37:18

0

屬性添加到報警

public bool Future 
{ get return (DateTime > DateTime.Now 
      || (EndRecurrency != null && EndRecurrency > DateTime.Now)); 
} 

當了更新報警呼叫未來NotifyPropertyChanged所有(或適當子集)。

然後使用DataTrigger或CollectionViewSource過濾器來隱藏它

<DataTrigger Binding="{Binding Path=Future, Mode=OneWay}" Value="False"> 
           <Setter Property="Visibility" Value="Collapsed"/> 
          </DataTrigger> 

過濾或隱藏是一種在表示層,所以應該離開你報警類別和報警收集全爲業務層和數據層。

由於ObservableCollection實現的iList應該是兼容的。

與你目前的模型FurtureAlarms不妨是一個列表。可以縮短語法

(alarms.Where(a => a.DateTime > DateTime.Now || (a.EndRecurrency != null && a.EndRecurrency > DateTime.Now))).toList(); 
0

在WPF中,結合正確的收藏需要結合於實現集合INotifyCollectionChanged它具有CollectionChanged事件每當一個項目被添加或從集合中刪除是應該被解僱。

所以建議您使用已經爲您實現該接口的ObservableCollection <T>類。而關於您使用的列表<T>變量,我認爲最好將它們切換到接口類型IList <T>,而不是由ObservableCollection實現,並且作爲附加好處,不需要ObservableCollection通知的應用程序部分將不會需要添加額外的引用或瞭解Observable集合。

相關問題