none
转换器Converter的非常规使用!!!! RRS feed

  • 问题

  • <CheckBox Margin="10" Content="EN SW" HorizontalAlignment="Stretch" VerticalAlignment="Center" IsChecked="{Binding Reg_SYSCTRL, Mode=TwoWay, Converter={StaticResource BitRangConv}, ConverterParameter=2-2}">
                                        <CheckBox.Background>
                                            <MultiBinding Converter="{StaticResource BitBrushConv}" ConverterParameter="2-2">
                                                <Binding Path="Reg_SYSCTRL" Mode="OneWay"/>
                                                <Binding Path="LastRegs[0]" Mode="OneWay"/>
                                            </MultiBinding>
                                        </CheckBox.Background>
                                    </CheckBox>

    这里是xaml代码,我们现在只讨论IsChecked属性的binding。

    class BitRangConverters : IValueConverter
        {
    
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
    
                String[] rang = (parameter as String).Split('-');
                if ((3 != rang.Length) && (2 != rang.Length))
                    return 0;
    
                int width = System.Convert.ToInt32(rang[1] as String, 10) -
                    System.Convert.ToInt32(rang[0] as String, 10) + 1;
                int offset = System.Convert.ToInt32(rang[0] as String, 10);
                Byte mask = (Byte)((Byte)Math.Pow(2, width) - 1);
                Byte baseVal = 0;
                if (3 == rang.Length)/* 目前只有0x03寄存器有起始值 */
                    baseVal = System.Convert.ToByte(rang[2] as String, 10);
    
                return (int)(((UInt32)value >> offset) & mask) - baseVal > 0 ?
                    (int)(((UInt32)value >> offset) & mask) - baseVal : 0;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
    
                String[] rang = (parameter as String).Split('-');
                if ((3 != rang.Length) && (2 != rang.Length))
                    return 0;
    
                /* 0为要设置的reg的值,1为位操作标志位,2为起始bit offset,3为结束bit offset */
                Byte[] cmd = new Byte[4];
                cmd[1] = 1;
                cmd[2] = System.Convert.ToByte(rang[0] as String, 10);
                cmd[3] = System.Convert.ToByte(rang[1] as String, 10);
    
                Byte width = 1;
                if (cmd[3] >= cmd[2])/* 保证不减出负数,从而溢出 */
                    width = (Byte)(cmd[3] - cmd[2] + 1);
                Byte offset = cmd[2];
                Byte mask = (Byte)((Byte)Math.Pow(2, width) - 1);
                Byte baseVal = 0;
                if (3 == rang.Length)/* 目前只有0x03寄存器有起始值 */
                    baseVal = System.Convert.ToByte(rang[2] as String, 10);
    
                if (value.GetType() == (new bool()).GetType())
                {/* bool类型要单独处理,不然类型不对 */
                    if (true == (bool)value)
                        cmd[0] = 1;
                    else
                        cmd[0] = 0;
                }
                else
                {
                    /* 校验位宽与输入值范围, 并且加上起始值 */
                    cmd[0] = (Byte)(((int)value & mask) + baseVal);
                }
                /* 把输入值搬移到对应的bit位上 */
                cmd[0] <<= offset;
    
                UInt32 ret = (UInt32)(cmd[0] + (cmd[1] << 8) + (cmd[2] << 16) + (cmd[3] << 24));
    
                return ret;
            }
        }

    这里是转换器。先简单介绍一下binding:

    Source是一个byte类型的值。

    parameter  "a-b":表示在这个byte值中的起始bit位。

    target是CheckBox的IsChecked属性。

    当source→target的时候:根据byte中相应的bit位的值判断IsChecked的值。

    但是当target→source的时候,我们只知道byte值中已知bit位的值,但是怎么确定整个byte的值呢?上面的代码的措施是,用了一个UInt32保存了这些信息返回,然后在set那个byte值得时候进行了重新解析(所以这里就把他当做了UInt32类型)

    public UInt32 this[UInt32 nindex]
                {
                    get { return regs[nindex]; }
                    set
                    {
                        Trace.Assert(null != rm);
                        Trace.Assert(0 <= nindex && 0xff >= nindex);
                        UInt16 newVal = rm.RegSetProc(value, regs[nindex]);
                        rm.RegValidityCheck(ref newVal, (Byte)nindex);
                        regs[nindex] = newVal;
    
                        Console.WriteLine("0x" + nindex.ToString("x2") + " : 0x" + regs[nindex].ToString("x2"));
                        rm.NotifyRegChanged(rm.GetRegNameByAddr((Byte)nindex));
                    }
                }

    但是这么做个人感觉不太好,请问大家是否有更好的办法?

    个人已有的思路是:是否可以在转换器中得到那一个byte值,然后利用这个byte值加上对应bit的值就可返回真正需要的值,那么那个source就用byte类型就可以了。怎么在转换器中的得到其他类中的属性呢???欢迎大家讨论

    2019年11月14日 3:11

全部回复

  • 或者大家是否还有其他思路,欢迎讨论

    2019年11月14日 3:15
  • 进展:

    1、在转换器初始化的时候是可以把其他类的数据传进去的。

    我在做实验的时候是用C#代码进行Binding的,所以转换器初始化也是用的C#代码(重构了一个带参的构造函数)。

    但是在xaml代码中,转换器是怎么初始化的呢?有大神懂相关知识吗?

    <Window.Resources>
            <local:MyConverter x:Key="sResource"/>
        </Window.Resources>
    目前只会这样使用转换器,但是这种形式的试验过是行不通的。

    2019年11月15日 3:10
  • 进展:

    1、在转换器初始化的时候是可以把其他类的数据传进去的。

    我在做实验的时候是用C#代码进行Binding的,所以转换器初始化也是用的C#代码(重构了一个带参的构造函数)。

    但是在xaml代码中,转换器是怎么初始化的呢?有大神懂相关知识吗?

    <Window.Resources>
            <local:MyConverter x:Key="sResource"/>
        </Window.Resources>
    目前只会这样使用转换器,但是这种形式的试验过是行不通的。

    Hi,

    你是想了解怎么使用带参数的转换器?我这个链接有使用。

    https://social.msdn.microsoft.com/Forums/zh-CN/b5785244-62d2-48da-9e0b-b3e6ff85b080/205402164427604293052030130340binding-converter?forum=wpfzhchs

    Best Regards,

    Alex


    如果您对Visual Studio 或Microsoft Azure相关产品感兴趣,请点击此链接,或扫描以下二维码注册获取相关信息。




    2019年11月17日 7:30
    版主