2016-05-16 9 views
0

Ich habe bereits eine Ausweichlösung für dieses Problem aus zeitlichen Gründen bei der Arbeit gemacht, obwohl ich immer noch für Lernzwecke bitten möchte.WPF Converter JSON Zeichenfolge zu mehreren Textfeldern

Also hatte ich dieses Problem, wo ich ein Editor-Bildschirm für einige Datensatzdaten machte, und in diesem Datensatz war ein Feld namens "Menge". Jedoch wurde es, wenn es entworfen wurde, zu einem Platzhalter gemacht, aber es bedeutete andere Dinge. Um es zu erklären, ist es eine SkuReference-Tabelle, die einen "Typ" hat, der definiert, ob es sich um eine "Menge pro Packung", "Rollenlänge" oder "CBC" handelt. Nun, für ‚Stück pro Packung‘ und ‚Roll Length‘, eine einfache Zahl funktioniert, aber für die ‚CBC‘ (das heißt, Corners/Grenzen/Zentren) die Daten als JSON-String-Objekt gespeichert ist:

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

Jetzt im WPF-Bildschirm, wenn die Daten als eine 'CBC' identifiziert werden, route ich die Daten in drei Textfelder, alle an die Eigenschaft 'Quantity' des übergeordneten Objekts gebunden und verwenden einen Konverter und Parameter zu identifizieren und I Setzen Sie den entsprechenden Wert in jedes Textfeld. Funktioniert gut.

Das Problem, das ich habe, ist, wenn Sie versuchen, den ConvertBack Teil des Konverters zu arbeiten. Ich erkannte, dass ich keinen Bezug auf die ursprüngliche Zeichenfolge-Eigenschaft habe, die ich bearbeiten kann und den neuen Wert bereitstellen oder auf die anderen Textfelder zugreifen kann, um einfach eine neue Zeichenfolge, die zurückgegeben werden soll, wiederherzustellen. Ich habe versucht, eine Lösung zu finden, vielleicht mit MultiBinding in meinem Kopf, aber ich konnte keine Antwort finden.

Ist das überhaupt möglich? BTW Ich habe am Ende nur neue Eigenschaften erstellt, die aufgeteilt wurden und wenn das übergeordnete Objekt eingestellt wurde und Daten umgeleitet wurde. Für zukünftige Referenz scheint es mir jedoch sauberer zu sein, nur die Originaldaten und einen Konverter ohne die zusätzliche Arbeit zu verwenden.

Unter anderen Code Referenz:

XAML ist UpsertSkuReference.Quantity die JSON-String oben

 <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> 

Converter

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; 
    } 
} 

Antwort

0

Wandler sind nicht sein soll so benutzt. Es gibt sauberere Wege. Ich würde Sie einen leichten größeren Refactoring vorschlagen:

  • erstellen 3 Eigenschaften: Borders, Corners und Centers, auf die Klasse, die die Zeichenfolge Quantity enthält; (SkuReference?)
  • Wenn Sie eines von ihnen einstellen, aktualisieren Sie die ; Wenn Sie die aktualisieren, versuchen Sie in einer CornerBorderCenterModel Instanz zu analysieren und aktualisieren Sie dann die 3 Eigenschaften mit den Werten dieser Instanz. All diese Arbeit macht die Implementierung der OnPropertyChanged Methode (siehe meinen Code später);
  • In der Ansicht, binden Sie alle TextBox nur mit der relativen Eigenschaft. Auf diese Weise benötigen Sie überhaupt keinen Konverter (dies funktioniert, wenn der externe DataContext die Instanz von UpsertSkuReference ist; andernfalls müssen Sie den DataContext des StackPanel auf diese Weise setzen: DataContext="{Binding UpsertSkuReference}", damit die Bindungen des 3 TextBoxes die Eigenschaften finden können das Objekt.

Die ganze Runde:

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> 

Beachten Sie, dass Quantity, Borders, Corners und Centers müssen Benachrichtigungen auslösen, wenn sie geändert werden (so wie ich gemacht, oder erweiterte Tools wie die Reaktiv-Bibliothek), andernfalls Die ganze Runde kann nicht funktionieren.

+0

Dies ist ziemlich nah an der Arbeit herum, die ich verwendet habe, da ich nicht warten konnte, außer dass, wenn eine der Eigenschaften geändert wurde, es die Eltern-JSON-Zeichenfolge neu erstellen würde. Ich denke, es ist nicht möglich, wie ich gehe. Zuerst dachte ich, es wäre eine nette Art, Dinge zu tun, und funktioniert wunderbar, wenn man runtergeht, aber ich kann einfach nicht wieder aufstehen. –