数据绑定,如 Unity 的行为

Data Binding like Behaviors with Unity

在我解释问题之前用一句话总结我的曲折问题。我怎样才能做到这一点,如果我从我的字典中的一个键更新一个值,它将触发与该 key/TextBinding 关联的 OnPropertyChanged 方法,或者我应该以不同的方式进行此操作

我在 WPF/MVVM 数据绑定方面有一些经验,所以理想的解决方案适用于我的项目:如果我的游戏中的值发生变化,它会自动更新 UI 当前显示的任何位置.

我有一个非常基本的地方可以开始使用字典查找 table 但可能有些人理解我需要的东西会更好

第一个代码块是可以视为附加到 UI 文本字段的 BindingBehavior(更准确地说是同一父游戏对象的组件)

如果我将 TextBinding 设置为一个值,我的 UI 会更改以反映它,但如果我通过我的字典更改一个值,我的字典似乎只包含分配给它的值的副本那个时候,并没有更新参考 "TextBinding"

编辑:我以某种方式丢失了一段文本,已修补

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;

public class BindingBehavior : MonoBehaviour
{
    public string BindingName;
    public string TextInitialValue;

    private string _textBinding;
    public string TextBinding
    {
        get
        {
            return _textBinding;
        }
        set
        {
            _textBinding = value;
            NotifyPropertyChanged(value);
        }
    }

    void NotifyPropertyChanged (string value)
    {
        this.gameObject.GetComponent<Text>().text = value;
    }

    // Use this for initialization
    void Start ()
    {
        TextBinding = TextInitialValue;
        UIManager.Instance.BindingLookUp.Add(BindingName, TextBinding);
        Debug.Log (BindingName + ", " + TextBinding + " was added to Binding Lookup Dictionary");
    }
}

Below is the separate class for readability

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using System.Collections.Generic;

public class UIManager 
{
    private static UIManager _instance;
    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UIManager();
            }
            return _instance;
        }
        set
        {
            _instance = value;
        }
    }

    public Dictionary<string, string> BindingLookUp = new Dictionary<string, string>();
}

编辑:第二次尝试使用 class 从其他地方阅读的关于堆栈溢出的一些建议(引用类型?)似乎仍然没有完成这项工作。

public class BindableString
{
    private string _stringValue;
    public string StringValue
    {
        get
        {
            return _stringValue;
        }
        set
        {
            _stringValue = value;
        }
    }

    public BindableString(string s)
    {
        StringValue = s;
    }
}

public class BindingBehavior : MonoBehaviour
{
    public string BindingName;
    public string TextInitialValue;

    private BindableString _textBinding;
    public BindableString TextBinding
    {
        get
        {
            return _textBinding;
        }
        set
        {
            _textBinding = value;
            NotifyPropertyChanged(value);
        }
    }

    void NotifyPropertyChanged (BindableString str)
    {
        this.gameObject.GetComponent<Text>().text = str.StringValue;
    }

    // Use this for initialization
    void Start ()
    {
        TextBinding = new BindableString( TextInitialValue);
        UIManager.Instance.BindingLookUp.Add(BindingName, TextBinding);
        Debug.Log (BindingName + ", " + TextBinding + " was added to Binding Lookup Dictionary");
    }
}

public class UIManager 
{
    private static UIManager _instance;
    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UIManager();
            }
            return _instance;
        }
        set
        {
            _instance = value;
        }
    }

    public Dictionary<string, BindableString> BindingLookUp = new Dictionary<string, BindableString>();
}

这是我为更新文本所做的调用

UIManager.Instance.BindingLookUp["ActiveCharacterActionPointsRemaining"] = new BindableString(_activeCharacter.actionPointsRemaining.ToString());

我认为你最好的选择是实现你自己的 ObservableDictionary class,它触发 PropertyChanged 事件,PropertyName 设置为 "Item[]"

这里有一个示例实现:http://blogs.microsoft.co.il/shimmy/2010/12/26/observabledictionarylttkey-tvaluegt-c/。关键部分是:

private const string CountString = "Count";
private const string IndexerName = "Item[]";
private const string KeysName = "Keys";
private const string ValuesName = "Values";

private void Insert(TKey key, TValue value, bool add)
{
    if (key == null)
        throw new ArgumentNullException("key");

    TValue item;
    if (Dictionary.TryGetValue(key, out item))
    {
        if (add)
            throw new ArgumentException("An item with the same key has already been added.");
        if (Equals(item, value))
            return;
        Dictionary[key] = value;

        OnCollectionChanged(NotifyCollectionChangedAction.Replace, new KeyValuePair<TKey, TValue>(key, value), new KeyValuePair<TKey, TValue>(key, item));
    }
    else
    {
        Dictionary[key] = value;
        OnCollectionChanged(NotifyCollectionChangedAction.Add, new KeyValuePair<TKey, TValue>(key, value));
    }
}

private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> changedItem)
{
    OnPropertyChanged();
    if (CollectionChanged != null)
        CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem));
}

private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> newItem, KeyValuePair<TKey, TValue> oldItem)
{
    OnPropertyChanged();
    if (CollectionChanged != null)
        CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItem, oldItem));
}

private void OnPropertyChanged()
{
    OnPropertyChanged(CountString);
    OnPropertyChanged(IndexerName);
    OnPropertyChanged(KeysName);
    OnPropertyChanged(ValuesName);
}

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

我想我现在有一个解决方案,我很乐意使用它来进行文本绑定,不过我会把它带到 Unity Answers 网站,看看是否有办法制作一个更通用的词典版本使用游戏对象或组件或其他更 'stable' 的解决方案。这是代码。事后看来,这似乎很明显,我不知道为什么我先尝试了这个。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;

public class BindingBehavior : MonoBehaviour
{
    public string BindingName;
    public string TextInitialValue;

    public Text TextComponent;

    public string TextValue
    {
        get
        {
            if (TextComponent == null)
            {
                TextComponent = this.gameObject.GetComponent<Text>();
            }
            return TextComponent.text;
        }
        set
        {
            if (TextComponent == null)
            {
                TextComponent = this.gameObject.GetComponent<Text>();
            }
            TextComponent.text = value;
        }
    }

    // Use this for initialization
    void Start ()
    {
        TextValue = TextInitialValue;
        UIManager.Instance.UITextBindings.Add(BindingName, TextComponent);
    }
}

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

public class UIManager 
{
    private static UIManager _instance;
    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UIManager();
            }
            return _instance;
        }
        set
        {
            _instance = value;
        }
    }

    public Dictionary<string, Text> UITextBindings = new Dictionary<string, Text>();
}

要更新 UI 文本,我只需拨打电话

UIManager.Instance.UITextBindings["ActiveCharacterActionPointsRemaining"].text = _activeCharacter.actionPointsRemaining.ToString();