2016-03-23 9 views
1

Ich arbeite mit Xamarin.Forms in einem PCL-Projekt.Wie kann ich feststellen, welcher Xamarin Forms Eintrag in einem ListView geändert wurde?

Ich habe eine Seite/Bildschirm, wo es ein ListView-Steuerelement gibt. Ich habe eine benutzerdefinierte DataTemplate für ViewCell erstellt.

Diese ViewCell hat verschiedene Steuerelemente: einige Labels, einen Button und auch einen Eintrag.

<ListView x:Name="lvProducts" > 
    <ListView.ItemTemplate> 
    <DataTemplate> 
     <ViewCell> 
     <StackLayout BackgroundColor="#FFFFFF" Orientation="Vertical"> 
      <Grid Padding="5"> 
      ... 
      <Button Grid.Row="0" Grid.Column="1" Text="X" 
        CommandParameter="{Binding MarkReference}" 
        Clicked="DeleteItemClicked" /> 
      ... 
      <StackLayout Grid.Row="2" Grid.ColumnSpan="2" Orientation="Horizontal" > 
       <Label Text="Ref.: " FontSize="24" FontAttributes="Bold" TextColor="#000000" /> 
       <Label Text="{Binding Reference}" FontSize="24" TextColor="#000000" /> 
      </StackLayout> 
      ... 
      <Entry Grid.Row="3" Grid.Column="1" Text="{Binding NumElements}" 
        Keyboard="Numeric" Placeholder="" FontSize="24" 
        HorizontalTextAlignment="Center" Focused="OnItemFocus"  
        Unfocused="OnItemUnfocus" /> 
     </Grid> 
     </StackLayout> 
     </ViewCell> 
    </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

Ich mag zwei Dinge mit dieser Eingangskontrolle erreichen, die ich nicht in der Lage zu erreichen bin:

Erstens, wenn ich ein neues Element hinzufügen, würde Ich mag, dass dieses neue Element seinen Eintrag hat den Fokus , bereit, mit der Eingabe zu beginnen.

Zweitens, wenn der Benutzer endet, um einen Wert in den Eintrag zu schreiben, möchte ich den Wert des dahinter ändern. Ich würde gerne wissen, welchen Eintrag von ListView geändert hat. Ich habe versucht, das Unfocused-Ereignis zu verwenden, aber in den Parametern der Methode, die gestartet wird, verfügt nur über einen Absenderparameter, der das Entry-Objekt zurückgibt, keine Referenz über das Modell, das gebunden hat.

public void OnItemUnfocus(object sender, EventArgs e) 
    { 
     Entry entry = (Entry)sender; 
     //Here I would like to know the model object that's binded 
     //with this Entry/CellView item 
    } 

Wie kann ich diese beiden Punkte erreichen?

+1

den zweiten Punkt betrifft, wenn Sie benötigen Wenn Sie auf das Datenobjekt zugreifen, können Sie 'OnBindingContextChanged' in der Zelle überschreiben und dann das Objekt mit' var object = (YourClass) BindingContext 'abrufen. Auf diese Weise können Sie jederzeit auf das Objekt in der Datenquelle zugreifen. – markusian

+1

Danke @markusian, ich habe deine Idee, und ich habe es benutzt. Ich habe das Entry-Steuerelement erweitert und ich in Unfocused Event verwendet. Funktioniert gut. – stivex

Antwort

-1

Für meine erste Frage habe ich einen Weg gefunden, es zu lösen. Ich weiß nicht, ob es die beste Lösung ist.

Ich habe Listview CustomListView erweitert, und ich habe hinzugefügt, und ein Wörterbuch der Zellen:

private Dictionary<string, Cell> dicCells; 

Außerdem habe ich außer Kraft gesetzt SetupContent und UnhookContent Methoden.

SetupContent wird ausgelöst, wenn eine neue Zelle hinzugefügt wurde, und eines seiner Parameter gibt mir die neue Zelle, die ich im Wörterbuch gespeichert habe. (MarkReference ist mein Schlüsselwert)

//When a new cell item has added, we save it into a dictionary 
    protected override void SetupContent(Cell content, int index) 
    { 
     base.SetupContent(content, index); 

     ViewCell vc = (ViewCell)content;    

     if (vc != null) 
     { 
      BasketProduct bp = (BasketProduct)vc.BindingContext; 
      if (bp != null) 
      { 
       this.dicCells.Add(bp.MarkReference, content); 
      }     
     } 

    } 

UnhookContent wird ausgelöst, wenn eine Zelle entfernt wurde. Ich entferne den Artikel, der in meinem Wörterbuch existiert.

//When a new cell item has removed, we remove from the dictionary 
    protected override void UnhookContent(Cell content) 
    { 
     base.UnhookContent(content); 

     ViewCell vc = (ViewCell)content; 

     if (vc != null) 
     { 
      BasketProduct bp = (BasketProduct)vc.BindingContext; 
      if (bp != null) 
      { 
       this.dicCells.Remove(bp.MarkReference); 
      } 
     } 

    } 

Dann habe ich eine Funktion erzeugt, die einen Eintrag (CustomEntry in meinem Fall) abruft, die das Objekt (BasketProduct in meinem Fall) enthält.

//Retrieves a CustomEntry control that are into the collection and represents the BasketProduct that we have passed 
    public CustomEntry GetEntry(BasketProduct bp) 
    { 
     CustomEntry ce = null; 

     if (bp != null && this.dicCells.ContainsKey(bp.MarkReference)) 
     { 
      ViewCell vc = (ViewCell)this.dicCells[bp.MarkReference]; 

      if (vc != null) 
      { 
       ce = (CustomEntry)((Grid)((StackLayout)vc.View).Children[0]).Children[4]; 
      } 

     } 

     return ce; 
    } 

Als ich den Fokus auf einen bestimmten Eintrag geben wollen, nenne ich diese Methode:

//Put the focus on the CustomEntry control that represents de BasketProduct that they have passed 
    public void SetSelected(BasketProduct bp, bool withDelay) 
    { 
     CustomEntry entry = null; 

     entry = GetEntry(bp); 

     if (entry != null) 
     { 
      if (withDelay) 
      { 
       FocusDelay(entry); 
      } else 
      { 
       entry.Focus(); 
      }         
     }    
    } 

Wenn ich die SetSelected() -Methode von ItemTapped Methode aufrufen, funktioniert gut, aber wenn ich rufe die Methode SetSelected() nach dem Hinzufügen eines Elements in der Auflistung, erhält der Eintrag nicht den Fokus. In diesem Fall habe ich einen Trick gemacht.

private async void FocusDelay(CustomEntry entry) 
    {    
     await Task.Delay(500); 
     entry.Focus(); 
    } 

Über zweite Frage, wie @markusian vorgeschlagen, habe ich den Eintrag (CustomEntry) Steuerung erweitert und in der Unfocused Veranstaltung habe ich getan, um diese:

private void CustomEntry_Unfocused(object sender, FocusEventArgs e) 
    { 
     try 
     { 
      //If the user leaves the field empty, we set the last value 
      BasketProduct bp = (BasketProduct)BindingContext; 
      if (this.Text.Trim().Equals(string.Empty)) 
      { 
       this.Text = bp.NumElements.ToString(); 
      } 
     } 
     catch (FormatException ex) { } 
    } 
3

Ich mag würde vorschlagen Sie Verhalten verwenden:

public class FocusBehavior : Behavior<Entry> 
{ 
    private Entry _entry; 

    public static readonly BindableProperty IsFocusedProperty = 
     BindableProperty.Create("IsFocused", 
           typeof(bool), 
           typeof(FocusBehavior), 
           default(bool), 
           propertyChanged: OnIsFocusedChanged); 

    public int IsFocused 
    { 
     get { return (int)GetValue(IsFocusedProperty); } 
     set { SetValue(IsFocusedProperty, value); } 
    } 

    protected override void OnAttachedTo(Entry bindable) 
    { 
     base.OnAttachedTo(bindable); 

     _entry = bindable; 
    } 

    private static void OnIsFocusedChanged(BindableObject bindable, object oldValue, object newValue) 
    { 
     var behavior = bindable as FocusBehavior; 
     var isFocused = (bool)newValue; 

     if (isFocused) 
     { 
      behavior._entry.Focus(); 
     } 
    } 
} 

<ListView x:Name="TasksListView" 
      ItemsSource={Binding Tasks} 
      RowHeight="200"> 
    <ListView.ItemTemplate> 
    <DataTemplate> 
     <ViewCell x:Name="ViewCell"> 
     <Grid x:Name="RootGrid" 
       Padding="10,10,10,0" 
       BindingContext="{Binding}"> 
      <Entry> 
       <Entry.Behaviors> 
       <helpers:FocusBehavior IsFocused="{Binding BindingContext.IsFocused, Source={x:Reference RootGrid}}"/> 
       </Entry.Behaviors> 
      </Entry> 
     </Grid> 
     </ViewCell> 
    </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

Und mein Modell:

public class TaskModel : INotifyPropertyChanged 
{ 
    private bool _isFocused; 

    public bool IsFocused 
    { 
     get { return _isFocused; } 
     set 
     { 
      _isFocused = value; 
      RaisePropertyChanged(); 
     } 
    } 

Und in Ansichtsmodell, nach dem neuen Artikel hinzufügen, legen Sie es IsFocused Eigenschaft auf true ist.

Das gleiche mit Verhalten, das Sie für TextChanged für Entry verwenden könnten.

+0

Vielen Dank @EgorGromadskiy! Sie haben mir geholfen, die Inspiration zu haben. Ich habe nie mit Verhaltensweisen gearbeitet. Ich muss es studieren. – stivex