2013-07-18 88 views
2

關於這個問題缺乏問題可能是代碼味道的一個指示,但是......是否有可能爲一個類和數據綁定編寫擴展方法,使其像屬性一樣?是否有可能將數據綁定到擴展方法?

這個假設是我提供了一個我不能從根本上改變的類結構,但是我想將它的一系列布爾屬性表示爲一個字符串用於顯示目的。

簡化的基類:

public class Transmission 
{ 
    public int ID { get; set; } 
    public bool Cancelled { get; set; } 
    public bool Stored { get; set; } 
    public bool Recorded { get; set; } 
} 

我的擴展方法:

public static class Extensions 
{ 
    public static string Status(this Transmission trans) 
    { 
     StringBuilder sb = new StringBuilder("|"); 
     if (trans.Cancelled) 
      sb.Append("| Cancelled "); 
     if (trans.Recorded) 
      sb.Append("| Recorded "); 
     if (trans.Stored) 
      sb.Append("| Stored "); 
     sb.Append("||"); 

     return sb.ToString(); 
    } 
} 

爲了進一步增加的複雜性,我傳遞的這些事情的清單,我試圖綁定到一個數據網格(XAML體驗嚴重受限)。

<GroupBox Header="Here is an amazing list of results for you to violate horribly."> 
    <DataGrid ItemsSource="{Binding Transmissions, Mode=OneWay}" AutoGenerateColumns="False"> 
     <DataGrid.Columns> 
      <DataGridTextColumn Width="*" Header="Local ID" Binding="{Binding ID, Mode=OneWay}"/> 
      <DataGridTextColumn Width="*" Header="Status" Binding="{Binding Status, Mode=OneWay}"/> 
     </DataGrid.Columns> 
    </DataGrid> 
</GroupBox> 

我測試了代碼,並且能夠毫無困難地綁定到ID。然而,'地位'根本沒有被收回。綁定到擴展屬性有一個技巧嗎?或者只是寫一個裝飾器/外觀類並綁定到它會更審慎?

+2

你不能綁定到擴展方法......實際上你不能綁定到任何方法,必須是一個屬性... – McGarnagle

+1

另外,沒有這種東西作爲「擴展屬性」 –

+2

@MarcGravell:不幸... –

回答

2

當你通過傳輸對象,你可以使用Facade模式並將其存儲在設計容器的列表...

public class TransmissionContainer : INotifyPropertyChanged 
{ 
    private readonly Transmission _transmission; 
    public TransmissionContainer(Transmission transmission) 
    { 
     _transmission = transmission; 
    } 
    private int _id; 
    public int Id 
    { 
     [DebuggerStepThrough] 
     get { return _transmission.ID; } 
     [DebuggerStepThrough] 
     set 
     { 
      if (value != _transmission.ID) 
      { 
       _transmission.ID = value; 
       OnPropertyChanged("Id"); 
      } 
     } 
    } 
    public bool Cancelled 
    { 
     [DebuggerStepThrough] 
     get { return _transmission.Cancelled } 
     [DebuggerStepThrough] 
     set 
     { 
      if (value != _transmission.Cancelled) 
      { 
       _transmission.Cancelled = value; 
       OnPropertyChanged("Cancelled"); 
       OnPropertyChanged("Status"); 
      } 
     } 
    } 
    public string Status 
    { 
     [DebuggerStepThrough] 
     get 
     { 
      StringBuilder sb = new StringBuilder("|"); 
      if (_transmission.Cancelled) 
       sb.Append("| Cancelled "); 
      if (_transmission.Recorded) 
       sb.Append("| Recorded "); 
      if (_transmission.Stored) 
       sb.Append("| Stored "); 
      sb.Append("||"); 
      return sb.ToString(); 
     } 
    } 
    // 
    // code in other properties here 
    // 
    #region INotifyPropertyChanged Implementation 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropertyChanged(string name) 
    { 
     var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null); 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
    #endregion 
} 

這是創建外牆的容器類到XAML中能透明地綁定。如圖所示,每個暴露的屬性只是回傳Transmission的私有實例中的值。通過INotifyPropertyChanged接口將更改中繼到WPF綁定引擎。

要創建一個實例,您可以使用原始傳輸類構造它。要綁定這些容器的集合,可以聲明一個類型爲TransmissionContainer的ObservableCollection。這樣做意味着除了屬性中的各種更改之外,還會綁定列表。

在這種方法中,您的'擴展'屬性只是另一個沒有設置器的暴露屬性。請注意,影響狀態的其他成員的更改將以「擴展」屬性的形式調用通知。在傳輸類的其餘成員編碼應該需要大約20分鐘...

+0

謝謝你這麼徹底地描述這個過程!如果一切正常,我會給它一個答案並將其標記爲答案。 – MadHenchbot

+1

它會工作給你如何描述這個問題。你的問題是一個純粹的立面解決方案,立面圖案有着傑出的血統。 :) –

5

這就是你通常使用的模式,如MVVM。您將屬性添加到基於模型且僅與視圖相關的視圖模型。視圖模型可以包含對模型的引用,以直接綁定到它的屬性或將它們映射到視圖模型上(對於解耦,我會選擇後者)。

+0

這實際上是我第一個使用MVVM的項目,所以這可能是一個愚蠢的問題,但是......鏡像我的*對象集合的最佳方法是什麼?基於原始傳輸模型創建一個新的容器類?這是否與Garry Vass在此主題中的回答相似? – MadHenchbot

+0

@MadHenchbot:你的集合將包含視圖模型(容器類),每個視圖模型都包含它的模型。它確實與Vass發佈的內容類似,他也很好地指出了你需要發佈更改通知的方式。另外,不要叫他們*線程*,這是一種侮辱,我們所做的最強烈的觀點*不*線程。 –

+0

拿了點。 :)感謝您的澄清! – MadHenchbot

相關問題