using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections;

namespace Misc
{
    public class BindingOperations
    {
        
        // 摘要:
        //     描述绑定中数据流的方向。
        public enum BindingMode
        {
            // 摘要:
            //     导致对源属性或目标属性的更改可自动更新对方。此绑定类型适用于可编辑窗体或其他完全交互式 UI 方案。
            TwoWay = 0,
            //
            // 摘要:
            //     当绑定源(源)更改时,更新绑定目标(目标)属性。如果要绑定的控件为隐式只读控件,则适用此绑定类型。例如,可以绑定到如股市代号之类的源。或者,可能目标属性没有用于进行更改(例如表的数据绑定背景色)的控件接口。如果不需要监视目标属性的更改,则使用
            //     System.Windows.Data.BindingMode.OneWay 绑定模式可避免 System.Windows.Data.BindingMode.TwoWay
            //     绑定模式的系统开销。
            OneWay = 1
        }
        /// <summary>
        /// 当绑定源(源)更改时,更新绑定目标(目标)属性
        /// </summary>
        /// <param name="src"></param>
        /// <param name="srcPropertyName"></param>
        /// <param name="target"></param>
        /// <param name="targetPropertyName"></param>
        public static void SetBinding(INotifyPropertyChanged src, string srcPropertyName, INotifyPropertyChanged target, string targetPropertyName) 
        {
            SetBinding(src, srcPropertyName, target, targetPropertyName, BindingMode.OneWay);
        }
        public static void SetBinding(INotifyPropertyChanged src, string srcPropertyName, IList target, int index) 
        {

            Type type_s = src.GetType();
            Type type_t = target.GetType();
            System.Reflection.PropertyInfo pi_s = type_s.GetProperty(srcPropertyName);
            if (pi_s == null)
                return;
            
            object obj = pi_s.GetValue(src,null);
            target[index] = obj;

            src.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == srcPropertyName)
                {
                    object o = pi_s.GetValue(src, null);
                    target[index] = obj;
                }
            };
                    
        }
        public static void SetBinding(INotifyPropertyChanged src, string srcPropertyName, Action func) 
        {
            func();
            src.PropertyChanged += (s, e) =>
            {
                if (srcPropertyName==e.PropertyName)
                {
                    func();
                }
            };
        }
        public static void SetBinding(INotifyPropertyChanged src, string[] srcPropertyNames, Action func) 
        {
            func();
            src.PropertyChanged += (s, e) =>
            {
                if (srcPropertyNames.Contains(e.PropertyName)) 
                {
                    func();
                }
            };
        }
        public static void SetBinding(INotifyPropertyChanged src, string srcPropertyName, INotifyPropertyChanged target, string targetPropertyName, BindingMode mode) 
        {
            Type type_s = src.GetType();
            Type type_t = target.GetType();
            System.Reflection.PropertyInfo pi_s = type_s.GetProperty(srcPropertyName);
            System.Reflection.PropertyInfo pi_t = type_t.GetProperty(targetPropertyName);
            if (pi_s == null || pi_t == null)
                return;
      
            switch (mode) 
            {
                case BindingMode.OneWay://src->target
                    {
                        object obj = pi_s.GetValue(src,null);
                        pi_t.SetValue(target, obj, null);

                        src.PropertyChanged += (s, e) =>
                        {
                            if (e.PropertyName == srcPropertyName)
                            {
                                object o = pi_s.GetValue(src, null);
                                pi_t.SetValue(target, o, null);
                            }
                        };
                    }break;
                case BindingMode.TwoWay://src->target then target->src
                    {
                        object obj = pi_s.GetValue(src,null);
                        pi_t.SetValue(target, obj, null);

                        src.PropertyChanged += (s, e) =>
                        {
                            if (e.PropertyName == srcPropertyName)
                            {
                                object o = pi_s.GetValue(s, null);
                                pi_t.SetValue(target, o, null);
                            }
                        };

                        target.PropertyChanged += (s, e) =>
                        {
                            if (e.PropertyName == targetPropertyName)
                            {
                                object o = pi_t.GetValue(s, null);
                                pi_s.SetValue(src, o, null);
                            }
                        };
                    }break;
            }
        }
    }

}