2015-09-16 14 views
7

Mam problem z powiązaniem danych w niestandardowym widoku w formularzach Xamarin z modelem widoku strony zawierającej.Powiązanie niestandardowego widoku w Xamarin.Forms

My Widok niestandardowy jest bardzo proste, parę etykiet reprezentujących parę kluczy wartość:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
      x:Class="KeyValueView"> 
    <Grid VerticalOptions="Start"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition /> 
      <ColumnDefinition /> 
     </Grid.ColumnDefinitions> 

     <Label x:Name="KeyLabel" Text="{Binding Key}" Grid.Column="0" HorizontalOptions="Start" /> 
     <Label x:Name="ValueLabel" Text="{Binding Value}" Grid.Column="1" HorizontalOptions="EndAndExpand" /> 
    </Grid> 
</ContentView> 

z kodem tyle:

public partial class KeyValueView : ContentView 
{ 
    public KeyValueView() 
    { 
     InitializeComponent(); 
     this.VerticalOptions = LayoutOptions.Start; 
     this.BindingContext = this; 
    } 

    public static readonly BindableProperty ValueProperty = 
       BindableProperty.Create<KeyValueView, string>(w => w.Value, default(string)); 

    public string Value 
    { 
     get {return (string)GetValue(ValueProperty);} 
     set {SetValue(ValueProperty, value);} 
    } 

    public static readonly BindableProperty KeyProperty = 
     BindableProperty.Create<KeyValueView, string>(w => w.Key, default(string)); 

    public string Key 
    { 
     get {return (string)GetValue(KeyProperty);} 
     set {SetValue(KeyProperty, value);} 
    } 
} 

To jest zużywana na stronie następująco:

<views:KeyValueView Key="Order Number" Value="{Binding document_number}" /> 

Problem polega na tym, że ciąg klucza jest wyświetlany zgodnie z oczekiwaniami, ale ciąg wartości nie jest. Próbowałem wymusić zdarzenie PropertyChanged na właściwość document_number, to nie pomogło. Próbowałem również wyraźnie, ustawiając właściwość Text na etykietach podczas seter właściwości klucz/wartość widoku niestandardowego:

public string Key 
    { 
     get {return (string)GetValue(KeyProperty);} 
     set { 
      SetValue(KeyProperty, value); 
      KeyLabel.Text = value; 
     } 
    } 

ponownie w tym nie pomaga, kod seter nigdy nie wydaje się stracony (I umieścić punkt przerwania na nim i nie został trafiony)

Jeśli mogę dodać poza kontrolą skrzynki takimi jak etykiety związanej bezpośrednio do nieruchomości na stronie, to wyświetla poprawnie:

<Label Text="{Binding document_number}"/> 
<views:KeyValueView Key="Order Number" Value="{Binding document_number}" /> 

Czy ktoś wyjaśnij, dlaczego tak się dzieje (lub raczej się nie dzieje)?

Odpowiedz

20

Nie przypisuj wiązań wewnętrznie w niestandardowych elementach sterujących. Użyj tego:

public partial class KeyValueView : ContentView 
{ 
    public KeyValueView() 
    { 
     InitializeComponent(); 
     this.VerticalOptions = LayoutOptions.Start; 
    } 

    public static readonly BindableProperty ValueProperty = 
     BindableProperty.Create<KeyValueView, string>(w => w.Value, default(string)); 

    public string Value 
    { 
     get {return (string)GetValue(ValueProperty);} 
     set {SetValue(ValueProperty, value);} 
    } 

    public static readonly BindableProperty KeyProperty = 
     BindableProperty.Create<KeyValueView, string>(w => w.Key, default(string)); 

    public string Key 
    { 
     get {return (string)GetValue(KeyProperty);} 
     set {SetValue(KeyProperty, value);} 
    } 
    protected override void OnPropertyChanged(string propertyName) 
    { 
     base.OnPropertyChanged(propertyName); 

     if (propertyName == ValueProperty.PropertyName) 
     { 
      ValueLabel.Text = Value; 
     } 
     if (propertyName == KeyProperty.PropertyName) 
     { 
      KeyLabel.Text = Key; 
     } 
    } 
} 

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
      x:Class="KeyValueView"> 
    <Grid VerticalOptions="Start"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition /> 
      <ColumnDefinition /> 
     </Grid.ColumnDefinitions> 

     <Label x:Name="KeyLabel" Grid.Column="0" HorizontalOptions="Start" /> 
     <Label x:Name="ValueLabel" Grid.Column="1" HorizontalOptions="EndAndExpand" /> 
    </Grid> 
</ContentView> 

Właściwości leczenia (np. Wartość) jako odniesienia do BindableProperty (ValueProperty). Jeśli zrobisz coś wewnątrz Settera wartości, BindableProperty nie zostanie o tym powiadomione ORAZ przeciwnie, jeśli zrobisz coś z BindableProperty (przypisz/zmień ValueProperty) - właściwość Setter wartości nie zostanie wywołany.

Jeśli chcesz obsłużyć właściwości PropertyChanged, masz nadpisanie tego (OnPropertyChanged) lub Actions (jako dodatkowe parametry podczas tworzenia BindableProperty).

+0

To jest dokładnie to, czego potrzebowałem, dzięki. Może stać się nieco kłopotliwy dla niestandardowego widoku z wieloma właściwościami wiążącymi, ale popatrzę na refaktor, kiedy dojdę do tego punktu. – MikeW

+0

Świetna odpowiedź. To działa jak urok. –

+0

To wstyd, że propertyChanged: z BindableProperty na statyczny, cały punkt dla właściwości niestandardowych ma być ponownie użyty, a dzięki tej statycznej metodzie możesz użyć tylko jednego niestandardowego elementu, ale twoje rozwiązanie działa jak wdzięk – dpineda

0

udało mi się uzyskać to do pracy, wykonując

public KeyValueView() 
{ 
    InitializeComponent(); 
    this.VerticalOptions = LayoutOptions.Start; 
    this.Content.BindingContext = this; 
} 

a następnie robi to w xaml.cs dla widoku używasz niestandardowego widoku:

public ParentView() 
{ 
    InitializeComponent(); 
    BindingContext = this; 
} 

Dla pole wejściowe, które dawało mi problemy, musiałem się upewnić, że parametr defaultBindingMode został ustawiony na TwoWay.

Powiązane problemy