WPF将JSON字符串转换为多个文本框

时间:2016-05-16 20:23:08

标签: c# json wpf xaml ivalueconverter

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

所以我遇到了这个问题,我在为一些记录数据制作一个编辑器屏幕,在这个记录中有一个名为'Quantity'的字段。但是,在设计时,它被设为数量占位符,但它意味着不同的东西。因此,为了解释,它是一个SkuReference表,它有一个'Type',用于定义它是'每包数量','滚动长度'还是'CBC'。好吧,对于'每包数量'和'滚动长度',一个简单的数字可以工作,但对于'CBC'(意思是角/边框/中心),数据存储为JSON字符串对象:

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

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

我遇到的问题是在尝试使用转换器的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;
    }
}

1 个答案:

答案 0 :(得分:0)

不应该像这样使用转换器。有更清洁的方法。我建议你稍微重做一下:

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

整轮:

TextBoxes

请注意,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> QuantityBordersCorners必须在更改时发出通知(就像我做的那样,或使用更高级的工具,如Reactive库)否则整轮都无法运作。