【问题标题】:Data Binding like Behaviors with Unity与 Unity 类似的数据绑定行为
【发布时间】:2015-03-02 13:14:52
【问题描述】:

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

我在 WPF/MVVM 数据绑定方面有一些经验,因此理想的解决方案适用于我的项目:如果我的游戏中的某个值发生更改,它将自动更新它当前显示在 UI 上的任何位置。

我有一个非常基本的地方可以开始使用字典查找表,但可能有些人明白我需要什么,这样会更好地工作

第一个代码块是BindingBehavior,可以看作是附加到UI文本字段(更精确一点是同一父游戏对象的组件)

如果我将 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");
    }
}

下面是可读性的单独类

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>();
}

编辑:第二次尝试使用一些建议中的类在其他地方读取堆栈溢出(引用类型?)似乎仍然没有做这项工作。

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());

【问题讨论】:

    标签: c# dictionary unity3d


    【解决方案1】:

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

    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();
    

    【讨论】:

      【解决方案2】:

      我认为你最好的办法是实现你自己的ObservableDictionary 类,该类会触发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));
      }
      

      【讨论】:

      • 谢谢,我试试看
      • 以下行 /t/t/t/t public class ObservableDictionary 有问题:IDictionary, INotifyCollectionChanged, INotifyPropertyChanged /t/t/t /t 看起来在我使用 System.ComponentModel 时它没有改变 INotifyCollection 并且没有解决它的选项,我需要做什么才能找到 INotifyCollectionChanged
      • 您需要引用System.ObjectModel 程序集。 msdn.microsoft.com/query/…
      • 我 100% 有这个引用,但我已经不再试图保存字符串,将字典从 更改为 其中 Text 是 UnityEngine 的一个实例.UI 文本类。到目前为止似乎有效,所以我想我会尝试制作不同的绑定行为类来处理文本、图像、滑块等。感谢您的帮助!
      猜你喜欢
      • 2011-08-25
      • 2019-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 1970-01-01
      • 2019-03-09
      • 1970-01-01
      相关资源
      最近更新 更多