2015-04-23 5 views
10

Ich erstelle eine plattformübergreifende Anwendung, die das dynamische Generieren und Binden von Spinner-Steuerelementen erfordert. Ich konnte das auf iOS- und Windows-Plattformen tun, habe aber Probleme mit Android. Wenn ich es richtig verstehe, muss ich einige Argumente an den Konstruktor von MvxSpinner - Kontext und Attrs übergeben, aber ich bin nicht in der Lage herauszufinden, wie kann ich das tun und was sollte dort übergeben werden. Außerdem kann ich die ItemsSource und SelectedItem nicht binden. Ich nehme an, dass ein neuer Bindungssatz erstellt werden muss (ähnlich wie bei der iOS-Version), aber ich bin nicht in der Lage, es auf Android herauszufinden. Kannst du mir bitte eine Wegbeschreibung geben?Programmgesteuertes Erstellen und Binden von Android-Spinnern in MvvmCross

Hier ist meine Quellcode von Windows-Version:

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

Und hier ist die iOS-Version (ist mehr oder weniger die gleiche Sache - auch wenn es nur die bestehenden Spinnereien löscht, anstatt sie wieder zu verwenden):

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

Teil (und nicht funktional) Entwurf für die Android-Version I ist jetzt haben wie folgt:

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 und https://github.com/MvvmCross/MvvmCross-Tutorials/blob /master/ApiExamples/ApiExamples.Droid/Resources/Layout/Test_Spinner.axml#L11 - beide verwenden Datenbindung statt Code dahinter. – Stuart

+0

Vielen Dank Stuart, das gibt mir die Lösung für den Datenbindungs-Teil der Frage, aber ich habe immer noch ein Problem mit der programmatischen Erstellung des MvxSpinner im Code. Wie kann das gemacht werden? Was sollte dem Konstruktor übergeben werden? –

Antwort

2
Hier

ist ein Beispiel dafür, wie ein mvxspinner von Code in Activity.OnCreate erstellen:

_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); 

Dann, wenn Sie Ihre LayoutInflaterProvider wollen könnte wie folgt aussehen:

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

    public LayoutInflater LayoutInflater { get; private set; } 
} 

ich zunächst bei dieser Suche tutorial.

+0

Vielen Dank für die Antwort, nur was ich vermisse ist der LayoutInflaterProvider Typ, wie kann ich darauf zugreifen? –

+0

Hoppla, das ist eigentlich eine eigene benutzerdefinierte Klasse. Sie können es hier finden: https://github.com/MvvmCross/MvvmCross-Tutorials/blob/386d6b7e672e3289f6227255180b15bbd89f1534/CrossLight/PluginUse/Mvvm/Framework/LayoutInFlaterProvider.cs. Ich werde meine Antwort auch aktualisieren. – PkL728