2015-04-23 8 views
10

Sto creando un'applicazione multipiattaforma che richiede la generazione dinamica e il binding dei controlli Spinner. Sono stato in grado di farlo su piattaforme iOS e Windows, ma ho problemi con Android. Se ho capito bene, devo passare alcuni argomenti al costruttore di MvxSpinner - contesto e attrs, ma non sono in grado di capire come posso farlo e cosa dovrebbe essere passato lì. Inoltre, non so come legare quindi ItemsSource e SelectedItem. Suppongo che debba essere creato un nuovo set di binding (in modo simile alla versione iOS), ma non sono in grado di capirlo su Android. Puoi per favore darmi delle indicazioni?Creazione programmatica e associazione di spinners Android in MvvmCross

Ecco il mio codice sorgente dalla versione di Windows:

private void InputColourAtlasChangedMessageHandler(InputColourAtlasChangedMessage message) 
{ 
    ColourAtlas selected = message.SelectedColourAtlas; 
    var vm = ViewModel as ColorMatchViewModel; 

    List<ComboBox> newComboboxes = new List<ComboBox>(); 
    var currentCount = ColourPickersContainer.Children.Count; 
    for (int i = currentCount; i < message.ColourCodePartCount; i++) 
    { 
     ComboBox cb = new ComboBox { Margin = new Thickness(0, 0, 10, 0), PlaceholderText = "choose" }; 
     Binding itemsSourceBinding = new Binding(); 
     itemsSourceBinding.Path = new PropertyPath("ColourPartLists[" + i + "]"); 
     Binding selectedItemBinding = new Binding(); 
     selectedItemBinding.Path = new PropertyPath("SelectedColourCodeParts[" + i + "]"); 
     selectedItemBinding.Mode = BindingMode.TwoWay; 
     cb.Tag = i; 
     ColourPickersContainer.Children.Add(cb); 
     cb.SetBinding(ComboBox.ItemsSourceProperty, itemsSourceBinding); 
     cb.SetBinding(ComboBox.SelectedItemProperty, selectedItemBinding); 
     cb.SelectionChanged += cb_SelectionChanged;         
     BindingOperations.SetBinding(cb, ComboBox.SelectedItemProperty, selectedItemBinding); 
     newComboboxes.Add(cb); 
    } 
    while (ColourPickersContainer.Children.Count > message.ColourCodePartCount) 
    { 
     ColourPickersContainer.Children.RemoveAt(ColourPickersContainer.Children.Count - 1); 
    } 
    _comboboxes = newComboboxes;    
} 

void cb_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    var cb = sender as ComboBox; 
    int changedIndex = (int)cb.Tag; 
    if (e.AddedItems.Count > 0) 
    { 
     (DataContext as ColorMatchViewModel).ColourCodePartChangedCommand.Execute(changedIndex); 
    } 
} 

Ed ecco la versione iOS (facendo più o meno la stessa cosa - anche se solo cancella i filatori esistenti invece di riutilizzo):

private void InputColourAtlasChangedMessageHandler(InputColourAtlasChangedMessage message) 
{ 
    ColourAtlas selected = message.SelectedColourAtlas; 
    ClearPickers(); 
    var currentSet = this.CreateBindingSet<ColorMatchView, ColorMatchViewModel>(); 
    for (int i = 0; i < message.ColourCodePartCount; i++) 
    { 
     var j = i; 
     UIPickerView picker = new UIPickerView(); 
     var pickerViewModel = new MvxPickerViewModel(picker); 
     picker.Model = pickerViewModel; 
     picker.ShowSelectionIndicator = true; 
     pickerViewModel.SelectedItemChanged += vm_SelectedItemChanged; 
     var textView = new PaddedUITextField(new RectangleF(10, 50 + i * 40, 300, 30)); 
     Add(textView); 
     textView.InputView = picker; 
     _pickers.Add(picker); 
     _textViews.Add(textView); 
     currentSet.Bind(textView).For(t => t.Text).To("SelectedColourCodeParts[" + i + "]"); 
     currentSet.Bind(pickerViewModel).For(p => p.ItemsSource).To("ColourPartLists[" + i + "]"); 
     currentSet.Bind(pickerViewModel).For(p => p.SelectedItem).To("SelectedColourCodeParts[" + i + "]"); 
     currentSet.Bind(pickerViewModel).For(p => p.SelectedChangedCommand).To(vm => vm.ColourCodePartChangedCommand).CommandParameter(j); 
    } 
    currentSet.Apply(); 
    UpdateLayout(View.Frame.Size); 
} 

private void ClearPickers() 
{ 
    foreach (var picker in _pickers) 
    { 
     var vm = picker.Model as MvxPickerViewModel; 
     vm.SelectedItemChanged -= vm_SelectedItemChanged; 
     picker.RemoveFromSuperview(); 
    } 
    foreach (var textView in _textViews) 
    { 
     textView.RemoveFromSuperview(); 
    } 
    _pickers.Clear(); 
    _textViews.Clear(); 
} 

parziale (e non funzionale) schema per la versione Android che ho adesso è la seguente:

private void InputColourAtlasChangedMessageHandler(InputColourAtlasChangedMessage message) 
     { 
      ColourAtlas selected = message.SelectedColourAtlas; 
      var layout = FindViewById<LinearLayout>(Resource.Id.spinnerList); 
      ClearPickers(); 

      for (int i = 0; i < message.ColourCodePartCount; i++) 
      { 
       MvxSpinner spinner = new MvxSpinner(Context??, Attrs??); 
       MvxAdapter adapter = new MvxAdapter(this); 

       spinner.ItemSelected += spinner_ItemSelected; 
       layout.AddView(spinner); 
       _spinners.Add(spinner); 
      } 
     } 

     void spinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e) 
     { 
      var changedIndex = _spinners.IndexOf(sender as MvxSpinner); 
      (DataContext as ColorMatchViewModel).ColourCodePartChangedCommand.Execute(changedIndex); 
     } 

     private void ClearPickers() 
     { 
      var layout = FindViewById<LinearLayout>(Resource.Id.spinnerList); 
      foreach (var spinner in _spinners) 
      { 
       spinner.ItemSelected -= spinner_ItemSelected; 
      } 
      layout.RemoveAllViews(); 
      _spinners.Clear(); 
     } 
+1

https://github.com/MvvmCross/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs#L138 e https://github.com/MvvmCross/MvvmCross-Tutorials/blob /master/ApiExamples/ApiExamples.Droid/Resources/Layout/Test_Spinner.axml#L11 - entrambi utilizzano l'associazione dati anziché il codice. – Stuart

+0

Grazie a Stuart, questo mi dà la soluzione alla parte vincolante dei dati della domanda, ma ho ancora problemi con la creazione progressiva di MvxSpinner nel codice. Come può essere fatto? Cosa dovrebbe essere passato al suo costruttore? –

risposta

2

Ecco un esempio su come creare un mvxspinner dal codice in Activity.OnCreate:

_bindingContext = new MvxAndroidBindingContext(this, new LayoutInflaterProvider(LayoutInflater), _viewModel); 
var view = (LinearLayout)_bindingContext.BindingInflate(Resource.Layout.Main, null); 
SetContentView(view); 
var spinner = new MvxSpinner(this, null, new MvxAdapter(this, _bindingContext)); 
view.AddView(spinner); 

Quindi se si voleva la vostra LayoutInflaterProvider potrebbe essere simile a questa:

public class LayoutInflaterProvider 
    : IMvxLayoutInflater 
{ 
    public LayoutInflaterProvider(LayoutInflater layoutInflater) 
    { 
     LayoutInflater = layoutInflater; 
    } 

    public LayoutInflater LayoutInflater { get; private set; } 
} 

Inizialmente sono stato a guardare questo tutorial.

+0

Grazie per la risposta, l'unica cosa che mi manca è il tipo LayoutInflaterProvider, come accedervi? –

+0

Oops spiacente che in realtà è la propria classe personalizzata. Puoi trovarlo qui: https://github.com/MvvmCross/MvvmCross-Tutorials/blob/386d6b7e672e3289f6227255180b15bbd89f1534/CrossLight/PluginUse/Mvvm/Framework/LayoutInflaterProvider.cs. Aggiornerò anche la mia risposta – PkL728