【问题标题】:WPF Converter JSON string to multiple textboxesWPF 转换器 JSON 字符串到多个文本框
【发布时间】:2023-03-28 21:41:01
【问题描述】:

由于工作时间限制,我已经为这个问题制定了解决方法,尽管我仍然想请求学习。

所以我遇到了这个问题,我正在为一些记录数据制作编辑器屏幕,并且在这条记录中有一个名为“数量”的字段。然而,在设计时,它是一个数量占位符,但它意味着不同的东西。所以解释一下,它是一个 SkuReference 表,它有一个“类型”,它定义了它是“每包数量”、“卷长”还是“CBC”。好吧,对于 'Quantity per Pack' 和 'Roll Length',可以使用一个简单的数字,但是对于 'CBC'(意思是角/边界/中心),数据存储为 JSON 字符串对象:

{ 'Corners': 10, 'Borders': 20, 'Centers': 30 }

现在在 WPF 屏幕上,如果数据被识别为“CBC”,我将数据路由到三个文本框,它们都绑定到父对象的“数量”属性,并使用转换器和参数来识别每一个我将适当的值放入每个文本框中。工作正常。

我遇到的问题是在尝试使用转换器的 ConvertBack 部分时。我意识到我没有对可以编辑和提供新值的原始字符串属性的引用,也没有访问其他文本框以重新构建要返回的新字符串。我试图想出一个解决方案,可能在我的脑海中使用 MultiBinding,但无法完全找到答案。

这甚至可能吗?顺便说一句,我最终只是创建了拆分的新属性,并且在设置父对象时解析并传递了数据。但是,为了将来参考,我觉得只使用原始数据和转换器而不需要额外的工作似乎更干净。

以下是其他代码供参考:

XAML,UpsertSkuReference.Quantity 是上面的 JSON 字符串

        <StackPanel Grid.Column="5">
            <TextBlock Text="CBC" />
            <StackPanel Orientation="Horizontal">
                <TextBox Width="30" Text="{Binding UpsertSkuReference.Quantity, ConverterParameter=co, Converter={StaticResource CBCToIndividualConverter}}" IsEnabled="{Binding CBCIsChecked}" />
                <TextBox Width="30" Margin="5,0,0,0" Text="{Binding UpsertSkuReference.Quantity, ConverterParameter=b, Converter={StaticResource CBCToIndividualConverter}}" IsEnabled="{Binding CBCIsChecked}" />
                <TextBox Width="30" Margin="5,0,0,0" Text="{Binding UpsertSkuReference.Quantity, ConverterParameter=ce, Converter={StaticResource CBCToIndividualConverter}}" IsEnabled="{Binding CBCIsChecked}" />
            </StackPanel>
        </StackPanel>

转换器

public class CBCToIndividualConverter : IValueConverter
{
    JavaScriptSerializer json = new JavaScriptSerializer();

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //--value = CBC JSON object string
        //--parameter = [co]: Corners, [b]: Borders, [ce]: Centers
        if (value != null)
        {
            if (parameter == null) { throw new Exception("CBCToIndividualConverter: parameter cannot be null"); }
            if (new string[] { "co", "b", "ce" }.Contains(parameter.ToString().ToLower()) == false)
            { throw new Exception("CBCToIndividualConverter: parameter must be 'co' for Corners, 'b' for Borders, or 'ce' for Centers"); }

            CornerBorderCenterModel cbc = json.Deserialize<CornerBorderCenterModel>(value.ToString());

            switch (parameter.ToString().ToLower())
            {
                case "co": { return cbc.Corners; }
                case "b": { return cbc.Borders; }
                case "ce": { return cbc.Centers; }
                default: { return null; }
            }
        }
        else { return null; }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            //--value = number for parameter type
            //--parameter = [co]: Corners, [b]: Borders, [ce]: Centers

            //--?? Uh Oh
        }
        return null;
    }
}

【问题讨论】:

    标签: c# json wpf xaml ivalueconverter


    【解决方案1】:

    转换器不应该这样使用。有更清洁的方法。我建议您进行更大的重构:

    • 在包含字符串QuantitySkuReference?)的类上创建3个属性:BordersCornersCenters
    • 当您设置其中任何一个时,更新Quantity;当您更新Quantity 时,您尝试解析CornerBorderCenterModel 实例,然后使用此实例的值更新3 个属性。所有这些工作都是在实现OnPropertyChanged 方法(稍后参见我的代码);
    • 在视图中,将每个TextBox 绑定到相关属性。这样,您根本不需要转换器(如果外部DataContextUpsertSkuReference 的实例,则此方法有效;否则,您必须这样设置StackPanelDataContextDataContext="{Binding UpsertSkuReference}",所以3TextBoxes的绑定可以找到对象上的属性。

    整个回合:

    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    
    namespace XXX
    {
        public class CornerBorderCenterModel
        {
            public int Corners { get; set; }
            public int Borders { get; set; }
            public int Centers { get; set; }
        }
    
        public class SkuReference : INotifyPropertyChanged
        {
            static JavaScriptSerializer json = new JavaScriptSerializer();
    
            private static string[] _jsonStringParts =
                new[] { nameof(Borders), nameof(Corners), nameof(Centers) };
    
            public SkuReference()
            {
                PropertyChanged += OnPropertyChanged;
            }
    
            public int Corners
            {
                get { return _Corners; }
                set
                {
                    if (_Corners != value)
                    {
                        _Corners = value;
                        RaisePropertyChanged();
                    }
                }
            }
            private int _Corners;
    
            public int Borders
            {
                get { return _Borders; }
                set
                {
                    if (_Borders != value)
                    {
                        _Borders = value;
                        RaisePropertyChanged();
                    }
                }
            }
            private int _Borders;
    
            public int Centers
            {
                get { return _Centers; }
                set
                {
                    if (_Centers != value)
                    {
                        _Centers = value;
                        RaisePropertyChanged();
                    }
                }
            }
            private int _Centers;
    
            private void UpdateCBCFromQuantity()
            {
                //if Quantity is a CBC and is not null do the following:
    
                var cbc = json.Deserialize<CornerBorderCenterModel>(_Quantity.ToString());
    
                if (cbc != null)
                {
                    Corners = cbc.Corners;
                    Borders = cbc.Borders;
                    Centers = cbc.Centers;
                }
            }
    
            public string Quantity
            {
                get { return _Quantity; }
                set
                {
                    if (_Quantity != value)
                    {
                        _Quantity = value;
                        RaisePropertyChanged();
                    }
                }
            }
            private string _Quantity;
    
            private void UpdateJsonStringFromCBC()
            {
                Quantity = string.Format(
                    "{{ 'Corners': {0}, 'Borders': {1}, 'Centers': {2} }}",
                    _Corners,
                    _Borders,
                    _Centers);
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
            {
                var handler = PropertyChanged;
    
                if (handler != null)
                    handler(this, new PropertyChangedEventArgs(propertyName));
            }
    
            private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (_jsonStringParts.Contains(e.PropertyName))
                    UpdateJsonStringFromCBC();
    
                else if (e.PropertyName == nameof(Quantity))
                    UpdateCBCFromQuantity();
            }
        }
    }
    
    
    <StackPanel Orientation="Horizontal" DataContext="{Binding UpsertSkuReference}">
      <TextBox Text="{Binding Corners}" IsEnabled="{Binding CBCIsChecked}" />
      <TextBox Text="{Binding Borders}" IsEnabled="{Binding CBCIsChecked}" />
      <TextBox Text="{Binding Centers}" IsEnabled="{Binding CBCIsChecked}" />
    </StackPanel>
    

    请注意,QuantityBordersCornersCenters 必须在它们发生变化时发出通知(就像我所做的那样,或者使用更高级的工具,如 Reactive 库),否则整轮都不能工作。

    【讨论】:

    • 这与我使用的工作非常接近,因为我等不及了,除了当任何属性发生更改时,它会重建父 json 字符串。我想这不可能像我走的那样。起初我认为这是一种简洁的做事方式,并且效果很好,但无法恢复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 2010-11-24
    • 1970-01-01
    • 2019-09-16
    • 1970-01-01
    • 2012-07-22
    • 1970-01-01
    相关资源
    最近更新 更多