2012-10-18 15 views
5

我打算在我的幾個類之間使用數據綁定。換句話說,我沒有綁定模型類和UI之間的值,而是在不同的類之間綁定變量。如何在C#代碼中進行數據綁定?

我已經閱讀了有關C#中幾個地方的數據綁定,但其中大多數都指向Windows窗體和源對象之間的綁定。

我還是C#的新手。這是我如何理解我該怎麼做:

首先,對於我的源對象,說有一個類名稱DataObject。源對象必須實現一個INotifyPropertyChange接口,然後在屬性health設置爲更改時觸發事件。我對此沒有任何問題。

現在,假設我有一個目標對象,稱爲CharacterClasslifeCharacterClass中的一個屬性,也是目標屬性,我想要綁定到源對象的health屬性。

如何將代碼中的兩個屬性(單向和雙向)綁定在一起,只有普通的.NET框架?

的背景資料,我爲什麼問這個問題有點:

萬一你認爲這是一個重複的問題,它不是。我已經通過SE搜索。關於代碼中數據綁定的其他問題在WPF或XAML的上下文中,這不適用於我。我也閱讀了MSDN上的幾篇文章,似乎我可以創建一個Binding對象,然後通過BindingOperations.SetBinding()綁定源和目標。但是,Binding類似乎是在System.Windows.Data.Binding名稱空間下的WPF庫的一部分。儘管我使用的是C#,但我懷疑我會奢侈地訪問WPF庫,因爲我主要使用C#作爲Unity3D中的一種腳本語言。我相信我只能訪問vanilla .Net框架。但是,我對此不太確定,因爲我對C#仍然陌生。

回答

7

儘管與使用的UI框架緊密結合的綁定有很多支持,但您仍然可以輕鬆編寫自己的綁定框架。

這是一個POC,它實現了兩個對象的屬性之間的單向綁定。

注意:這只是其中一種可能的方式,POC最好(可能需要對高性能/生產場景進行微調),並且使用.Net 2.0類和接口,而不依賴任何UI框架('香草'.net框架在你的話:))。一旦你明白這一點,你可以很容易地擴展,以支持雙向綁定以及

class Program 
{ 
    public static void Main() 
    { 
     Source src = new Source(); 
     Destination dst = new Destination(src); 
     dst.Name = "Destination"; 
     dst.MyValue = -100; 
     src.Value = 50; //changes MyValue as well 
     src.Value = 45; //changes MyValue as well 
     Console.ReadLine(); 
    } 
} 

//A way to provide source property to destination property 
//mapping to the binding engine. Any other way can be used as well 
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 
internal class BindToAttribute : Attribute 
{ 
    public string PropertyName 
    { 
     get; 
     private set; 
    } 

    //Allows binding of different properties to different sources 
    public int SourceId 
    { 
     get; 
     private set; 
    } 

    public BindToAttribute(string propertyName, int sourceId) 
    { 
     PropertyName = propertyName; 
     SourceId = sourceId; 
    } 
} 

//INotifyPropertyChanged, so that binding engine knows when source gets updated 
internal class Source : INotifyPropertyChanged 
{ 
    private int _value; 
    public int Value 
    { 
     get 
     { 
      return _value; 
     } 
     set 
     { 
      if (_value != value) 
      { 
       _value = value; 
       Console.WriteLine("Value is now: " + _value); 
       OnPropertyChanged("Value"); 
      } 
     } 
    } 

    void OnPropertyChanged(string propertyName) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

internal class Destination 
{ 
    private BindingEngine<Destination> _binder; 

    private int _myValue; 

    [BindTo("Value", 1)] 
    public int MyValue 
    { 
     get 
     { 
      return _myValue; 
     } 
     set 
     { 
      _myValue = value; 
      Console.WriteLine("My Value is now: " + _myValue); 
     } 
    } 

    //No mapping defined for this property, hence it is not bound 
    private string _name; 
    public string Name 
    { 
     get 
     { 
      return _name; 
     } 
     set 
     { 
      _name = value; 
      Console.WriteLine("Name is now: " + _name); 
     } 
    } 

    public Destination(Source src) 
    { 
     //Binder for Source no 1 
     _binder = new BindingEngine<Destination>(this, src, 1); 
    } 
} 

internal class BindingEngine<T> 
{ 
    private readonly T _destination; 
    private readonly PropertyDescriptorCollection _sourceProperties; 
    private readonly Dictionary<string, PropertyDescriptor> _srcToDestMapping; 

    public BindingEngine(T destination, INotifyPropertyChanged source, int srcId) 
    { 
     _destination = destination; 

     //Get a list of destination properties 
     PropertyDescriptorCollection destinationProperties = TypeDescriptor.GetProperties(destination); 

     //Get a list of source properties 
     _sourceProperties = TypeDescriptor.GetProperties(source); 

     //This is the source property to destination property mapping 
     _srcToDestMapping = new Dictionary<string, PropertyDescriptor>(); 

     //listen for INotifyPropertyChanged event on the source 
     source.PropertyChanged += SourcePropertyChanged; 

     foreach (PropertyDescriptor property in destinationProperties) 
     { 
      //Prepare the mapping. 
      //Add those properties for which binding has been defined 
      var attribute = (BindToAttribute)property.Attributes[typeof(BindToAttribute)]; 
      if (attribute != null && attribute.SourceId == srcId) 
      { 
       _srcToDestMapping[attribute.PropertyName] = property; 
      } 
     } 
    } 

    void SourcePropertyChanged(object sender, PropertyChangedEventArgs args) 
    { 
     if (_srcToDestMapping.ContainsKey(args.PropertyName)) 
     { 
      //Get the destination property from mapping and update it 
      _srcToDestMapping[args.PropertyName].SetValue(_destination, _sourceProperties[args.PropertyName].GetValue(sender)); 
     } 
    } 
} 

enter image description here

0

我相信我只能訪問到香草Net框架

現實情況是,數據綁定在UI使用。所以,如果有人談論數據綁定,那麼他會自動暗示「數據綁定在[UI Framework名稱]中」。

您可能會考慮使用對象映射而不是數據綁定。

+0

其實,是的,你說得對數據UI結合之中。在我的情況下,我正在構建一個UI,但不是使用Windows窗體。而我所指的所有這些*目標對象都是我的UI類。所以我希望的是可以在我自己的非WinForm UI上實現的「自定義」排序數據綁定技術。 – Carven

+0

@xEnOn:主要問題是綁定引擎與UI框架內部緊密結合。例如,WPF綁定使用依賴屬性,所以,如果你想使用它,你必須編寫你的UI類成爲'DependencyObject'後裔。我認爲,你應該寫自己的綁定引擎。 – Dennis

+0

我明白了。謝謝!看起來我沒有運氣使用C#的現有數據綁定引擎。 :(猜猜我必須研究如何編寫我自己的綁定引擎。也許我會在這裏提出一個新問題,以瞭解數據綁定引擎如何在引擎蓋下工作,給我自己一個想法,即如何編寫數據綁定引擎。非常感謝Dennis。:) – Carven

相關問題