7

いくつかのクラス間でデータ バインディングを使用するつもりです。つまり、モデル クラスと UI の間で値をバインドするのではなく、異なるクラス間で変数をバインドします。

C# でのデータ バインディングについていくつかの場所で読んだことがありますが、それらのほとんどは、Windows フォームとソース オブジェクトの間のバインディングについて言及しています。

私はまだC#に不慣れです。これは私が何をすべきかを理解する方法です:

まず、ソース オブジェクトについて、 のクラス名があるとしDataObjectます。ソース オブジェクトはINotifyPropertyChangeインターフェイスを実装し、プロパティ が変更されるたびにイベントをトリガーするhealth必要があります。私はこれで問題ありません。

ここで、 というターゲット オブジェクトがあるとしますCharacterClasslifeは のプロパティであり、ソース オブジェクトのプロパティにバインドするターゲット プロパティCharacterClassでもあります。health

通常の .NET フレームワークのみを使用して、コード内で 2 つのプロパティ (一方向と双方向の両方) をバインドするにはどうすればよいですか?

なぜ私がこの質問をするのかについての背景情報:

これが重複した質問だと思われる場合に備えて、そうではありません。SEで検索しました。コード内のデータバインディングに関するその他の質問は、WPF または XAML のコンテキストにあり、これは私には向いていません。また、MSDN のいくつかの記事を読みましたが、Bindingオブジェクトを作成し、ソースとターゲットをBindingOperations.SetBinding(). ただし、Bindingクラスは の名前空間の下にある WPF ライブラリの一部のようです System.Windows.Data.Binding。私は C# を使用していますが、Unity3D 内のスクリプト言語として主に C# を使用しているため、WPF ライブラリにアクセスする余裕があるとは思えません。バニラの .Net フレームワークにしかア​​クセスできないと思います。しかし、私はまだC#に慣れていないので、これについてはよくわかりません。

4

2 に答える 2

9

使用されている UI フレームワークと緊密に結合されたバインディングが多数サポートされていますが、独自のバインディング フレームワークを簡単に作成することもできます。

以下は、2 つのオブジェクトのプロパティ間の一方向バインディングを実装する POC です。

注: これは考えられる方法の 1 つにすぎません。せいぜい 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));
        }
    }
}

ここに画像の説明を入力

于 2012-10-18T10:52:24.793 に答える
0

私はバニラの.Netフレームワークにしかア​​クセスできないと思います

現実には、データバインディングはUIで使用されます。したがって、誰かがデータバインディングについて話す場合、彼は自動的に「[UIフレームワーク名]のデータバインディング」を暗示します。

データバインディングの代わりに、オブジェクトからオブジェクトへのマッピングを検討することもできます。

于 2012-10-18T05:55:36.100 に答える