【wpf】枚举的绑定最易用法 和 全局静态绑定的应用

背景

        有时我们做配置界面的时候,有很多配置项是枚举。通过我们会用一个Combobox实现,如果能直接用Combobox绑定枚举,那将会非常方便。这里绑定将涉及到两个方面,一个是数据源的绑定,还有就是当前选择项的绑定。最后我们要将选择项的信息进行保存,下次打开的时候就刚好是我们上次选择的项。

枚举数据源的绑定

        要想直接绑定枚举作为源,我们得首先准备一个类,这里我直接给出源代码,内容可以先不用理解。

 public class EnumBindingSourceExtension : MarkupExtension
    {
        private Type _enumType;

        public Type EnumType
        {
            get { return _enumType; }
            set
            {
                if (value != _enumType)
                {
                    if (null != value)
                    {
                        var enumType = Nullable.GetUnderlyingType(value) ?? value;
                        if (!enumType.IsEnum)
                        {
                            throw new ArgumentException("Type must bu for an Enum");
                        }

                    }

                    _enumType = value;
                }
            }
        }

        public EnumBindingSourceExtension()
        {

        }

        public EnumBindingSourceExtension(Type enumType)
        {
            EnumType = enumType;
        }
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (null == _enumType)
            {
                throw new InvalidOperationException("The EnumTYpe must be specified.");
            }

            var actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType;
            var enumValues = Enum.GetValues(actualEnumType);

            if (actualEnumType == _enumType)
            {
                return enumValues;
            }

            var tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1);
            enumValues.CopyTo(tempArray, 1);

            return tempArray;
        }
    }

然后在前台引用这个类,并且指点你声明得枚举类型即可:

这里有个小疑惑,就是我声明的类叫做EnumBindingSourceExtension,但是这里绑定的时候却可以写成(EnumBindingSource),也就是Extension 可以省略。所以不管你是否带上Extension 绑定都是工作的。

<ComboBox 
ItemsSource="{Binding Source={tools:EnumBindingSource {x:Type vm:MaskDetection}}}"/>

此时你就会发现已经绑定成功了!就是这么简单!

 枚举选择项的绑定

<ComboBox 
SelectedValue="{Binding saveInfo.enumMaskDetection, Source={x:Static md:GlobalData.Instance}}"

ItemsSource="{Binding Source={tools:EnumBindingSource {x:Type vm:MaskDetection}}}"/>

注意这里一定要使用SelectedValue,而不是 SelectedItem。至于:

saveInfo.enumMaskDetection, Source={x:Static md:GlobalData.Instance}

这句话其实是静态绑定的语法。  因为这些选择项作为配置,都是需要保存的,所以实现了一个单例模式的全局类(GlobalData)以及信息类(SaveInfo ),专门用于保存全局变量。

全局静态绑定

构建保存数据类

首先我构造一个信息类,这里面都声明的是枚举变量

public class SaveInfo 
    {

        public ColorSpace enumColorSpace { get; set; }
        public Illuminant enumIlluminant { get; set; }
        public Observer enumObserver { get; set; }

        public MeasurementMethod enumMeasurementMethod { get; set; }
        public MeasurementArea enumMeasurementArea { get; set; }
        public SpecularComponent enumSpecularComponent { get; set; }
        public MaskDetection enumMaskDetection { get; set; }

    }

和界面的中的选择项是一一对应的: 

最终这些选项选择的内容都会保存到该类中。

构建全局类

public class GlobalData
{
    /// <summary>
    /// 单例模式
    /// </summary>
    public static GlobalData Instance { private set; get; } = new GlobalData();

    public SaveInfo saveInfo { get; set; }

    private GlobalData()
    {
        var a = JsonConfigCtrl.Read<SaveInfo>("GlobalData");
        if (a == null)
        {
            saveInfo = new SaveInfo();
        }
        else
        {
            saveInfo = a;
        }
    }

    public void Save()
    {
        JsonConfigCtrl.Save<SaveInfo>(saveInfo, "GlobalData");
    }
}

序列化和反序列化

这里,要说明的是这个GlobalData是一个单例模式的类,注意他的构造函数是私有类型(确保了单例)。但是这会导致一个问题,就是无法序列化,因为序列要求有一个public的无参构造函数!

其实直接序列化GlobalData也不好,所以我用单独建立了SaveInfo 类,然后将SaveInfo 类作为他的成员对象!

然后在构造GlobalData时候,反序列化SaveInfo,由于做了静态绑定,所以反序列化SaveInfo后,界面会跟着配置改变。(这里注意,首次的数据到界面的同步,绑定是不需要通知函数的!而界面到数据同步是绑定默认的)。

在save里,我们继续序列化操作,将当前界面的数据保存到本地。

后台使用配置变量

由于直接绑定的就是枚举类型,所以无需转换直接赋值就好了!!!

setCalcCondition.ColorSpace = GlobalData.Instance.saveInfo.enumColorSpace;
setCalcCondition.Illuminant = GlobalData.Instance.saveInfo.enumIlluminant;
setCalcCondition.Observer = GlobalData.Instance.saveInfo.enumObserver;

小结

        通过这种方式绑定枚举、配置参数的使用,以及序列化和反序列化,真的是超级方便。

附录

序列化的相关代码

namespace ColorTest.Tools
{
    public class JsonConfigCtrl
    {
        static JsonSerializerOptions options;

        static JsonConfigCtrl()
        {
            options = new JsonSerializerOptions();
            options.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All);
        }

        /// <summary>
        /// 序列化操作  
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        static public void Save<T>(T obj, string filename = "config")
        {
            string _filePath = Directory.GetCurrentDirectory() + $"\\Config\\{filename}.json";
            FileInfo fi = new FileInfo(_filePath);
            if (!Directory.Exists(fi.DirectoryName))
            {
                Directory.CreateDirectory(fi.DirectoryName);
            }


            //StreamWriter yamlWriter = File.CreateText(_filePath);


            string str = System.Text.Json.JsonSerializer.Serialize(obj, options);
            str = JsonHelper.FormatJson(str);
            File.WriteAllText(_filePath, str);



            //Serializer yamlSerializer = new Serializer();
            //yamlSerializer.Serialize(yamlWriter, obj);
            //yamlWriter.Close();
        }

        /// <summary>
        /// 泛型反序列化操作  
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="FileNotFoundException"></exception>
        static public T Read<T>(string filename = "config") where T : class, new()
        {
            string _filePath = Directory.GetCurrentDirectory() + $"\\Config\\{filename}.json";
            if (!File.Exists(_filePath))
            {
                return default;
            }


            //读取持久化对象  
            try
            {
                T info = JsonSerializer.Deserialize<T>(File.ReadAllText(_filePath));

                return info;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return default;
            }
        }
    }


    public class JsonHelper
    {
        private const string INDENT_STRING = "    ";
        public static string FormatJson(string str)
        {
            var indent = 0;
            var quoted = false;
            var sb = new StringBuilder();
            for (var i = 0; i < str.Length; i++)
            {
                var ch = str[i];
                switch (ch)
                {
                    case '{':
                    case '[':
                        sb.Append(ch);
                        if (!quoted)
                        {
                            sb.AppendLine();
                            Enumerable.Range(0, ++indent).MyForEach(item => sb.Append(INDENT_STRING));
                        }
                        break;
                    case '}':
                    case ']':
                        if (!quoted)
                        {
                            sb.AppendLine();
                            Enumerable.Range(0, --indent).MyForEach(item => sb.Append(INDENT_STRING));
                        }
                        sb.Append(ch);
                        break;
                    case '"':
                        sb.Append(ch);
                        bool escaped = false;
                        var index = i;
                        while (index > 0 && str[--index] == '\\')
                            escaped = !escaped;
                        if (!escaped)
                            quoted = !quoted;
                        break;
                    case ',':
                        sb.Append(ch);
                        if (!quoted)
                        {
                            sb.AppendLine();
                            Enumerable.Range(0, indent).MyForEach(item => sb.Append(INDENT_STRING));
                        }
                        break;
                    case ':':
                        sb.Append(ch);
                        if (!quoted)
                            sb.Append(" ");
                        break;
                    default:
                        sb.Append(ch);
                        break;
                }
            }
            return sb.ToString();
        }



    }

    static class Extensions
    {
        public static void MyForEach<T>(this IEnumerable<T> ie, Action<T> action)
        {
            foreach (var i in ie)
            {
                action(i);
            }
        }
    }

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code bean

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值