2012-10-18 50 views
5

Tôi định sử dụng ràng buộc dữ liệu giữa một vài lớp học của mình. Nói cách khác, tôi không ràng buộc các giá trị giữa một lớp mô hình và giao diện người dùng, nhưng để ràng buộc các biến giữa các lớp khác nhau.Làm cách nào để gắn kết dữ liệu bằng mã với C#?

Tôi đã đọc về ràng buộc dữ liệu trong C# ở một số địa điểm, nhưng hầu hết trong số đó là đề cập đến ràng buộc giữa Windows Form và đối tượng nguồn.

Tôi vẫn còn mới đối với C#. Đây là cách tôi hiểu những gì tôi nên làm:

Đầu tiên, đối tượng nguồn của tôi, có tên lớp là DataObject. Đối tượng nguồn phải triển khai giao diện INotifyPropertyChange và sau đó kích hoạt sự kiện bất cứ khi nào thuộc tính, health, được đặt để thay đổi. Tôi không có vấn đề với điều này.

Bây giờ, giả sử tôi có đối tượng đích đích được gọi là CharacterClass. life là tài sản ở CharacterClass và cũng là thuộc tính mục tiêu mục tiêu mà tôi muốn liên kết với thuộc tính nguồn của đối tượng nguồn là health.

Làm cách nào để liên kết hai thuộc tính với nhau (cả hai chiều và hai chiều) trong mã chỉ với khung công tác .NET thông thường?

Một chút thông tin cơ bản về lý do tại sao tôi hỏi câu hỏi này:

Chỉ trong trường hợp bạn nghĩ rằng đây là một câu hỏi trùng lặp, nó không phải. Tôi đã tìm kiếm thông qua SE. Các câu hỏi khác về databinding trong mã là trong bối cảnh của WPF hoặc XAML, mà không phải dành cho tôi. Tôi cũng đã đọc một số bài viết trên MSDN và có vẻ như tôi có thể tạo ra một đối tượng Binding, và sau đó ràng buộc nguồn và đích thông qua BindingOperations.SetBinding(). Tuy nhiên, lớp Binding dường như là một phần của thư viện WPF dưới không gian tên là System.Windows.Data.Binding. Mặc dù tôi đang sử dụng C#, tôi nghi ngờ tôi sẽ có sự sang trọng để truy cập vào các thư viện WPF bởi vì tôi chủ yếu sử dụng C# như là một ngôn ngữ kịch bản trong Unity3D. Tôi tin rằng tôi chỉ có quyền truy cập vào khung công tác vani .Net. Nhưng, tôi không chắc lắm về điều này vì tôi vẫn còn mới đối với C#.

Trả lời

7

Mặc dù có rất nhiều hỗ trợ cho các ràng buộc được kết hợp chặt chẽ với khung giao diện người dùng đang được sử dụng, bạn vẫn có thể dễ dàng viết khung ràng buộc của riêng bạn.

Đây là một POC thực hiện liên kết một chiều giữa các thuộc tính của hai đối tượng. Lưu ý: Đây chỉ là một trong những cách có thể, một POC tốt nhất (có thể cần tinh chỉnh cho kịch bản sản xuất/hiệu suất cao) và sử dụng các lớp và giao diện Net 2.0 không phụ thuộc vào bất kỳ khung giao diện người dùng nào (' vani '.net framework trong lời nói của bạn :)).Một khi bạn đã hiểu điều này, bạn có thể dễ dàng mở rộng này để hỗ trợ 2 chiều ràng buộc cũng

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

Tôi tin rằng tôi chỉ có quyền truy cập vào các khuôn khổ vani Net

Thực tế là dữ liệu ràng buộc được sử dụng trong giao diện người dùng. Vì vậy, nếu có ai nói về ràng buộc dữ liệu, thì anh ta sẽ tự động ngụ ý "ràng buộc dữ liệu trong [UI Framework name]".

Bạn có thể xem xét ánh xạ đối tượng đến đối tượng thay vì ràng buộc dữ liệu.

+0

Trên thực tế, có, bạn có quyền về dữ liệu ràng buộc hạnh phúc cho UI. Trong tình huống của tôi, tôi đang xây dựng một giao diện người dùng, nhưng không phải với Biểu mẫu Windows. Và tất cả những đối tượng mục tiêu * mà tôi đã đề cập đến chủ yếu là các lớp UI của tôi. Vì vậy, những gì tôi hy vọng là cho một "tùy chỉnh" của kỹ thuật sắp xếp dữ liệu ràng buộc mà tôi có thể thực hiện vào giao diện người dùng không WinForm của riêng tôi. – Carven

+0

@xEnOn: vấn đề chính là các công cụ liên kết được kết hợp chặt chẽ với các khung nội bộ UI. Ví dụ, WPF ràng buộc sử dụng thuộc tính phụ thuộc, vì vậy, nếu bạn muốn sử dụng nó, bạn phải viết các lớp UI của bạn là con cháu 'DependencyObject'. Tôi nghĩ rằng, bạn nên viết động cơ ràng buộc của riêng bạn. – Dennis

+0

Tôi hiểu. Cảm ơn! Có vẻ như tôi không có may mắn khi sử dụng công cụ ràng buộc dữ liệu hiện có của C#. Có lẽ tôi sẽ đưa ra một câu hỏi mới ở đây để hiểu cách các công cụ liên kết dữ liệu hoạt động như thế nào dưới mui xe, để tạo cho tôi một ý tưởng làm thế nào tôi có thể viết một ràng buộc dữ liệu Cảm ơn rất nhiều, Dennis. :) – Carven

Các vấn đề liên quan