2016-07-07 6 views
2

I App vereinfacht mein Problem zu zeigenÄndern Viewmodel

Wenn ich Schaltfläche klicken, wird es Text Eigenschaft ViewModel und TextBlock.Text ändert aktualisiert wird.

MainPage.xaml

<StackPanel> 
    <Button Click="ButtonBase_OnClick">Button to change text</Button> 
    <TextBlock Text="{x:Bind ViewModel.Text, Mode=OneWay}"></TextBlock> 
</StackPanel> 

MainPage.xaml.cs

public MainPage() 
    { 
     ViewModel = new ViewModel(); 
     this.InitializeComponent(); 
    } 
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
    { 
     ViewModel.Text = "x:Bind works"; 
    } 

Ansichtsmodell Klasse hat eine String-Eigenschaft (Text) und implementiert INotifyPropertyChange Schnittstelle.


Problem beginnt, wenn ViewModel nicht in Ctor gesetzt ist (dh Ansichtsmodell ist null und in der Laufzeit geändert):

public MainPage() 
    { 
     //ViewModel = new ViewModel();//this line has been removed 
     this.InitializeComponent(); 
    } 
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
    { 
     ViewModel = new ViewModel();//this line has been added 
     ViewModel.Text = "x:Bind does not work"; 
    } 

complited Bindung nicht funktioniert (Text nicht verändert wird) und ich konnte nicht herausfinden, warum es so ist ... Ich muss viewModel von null ändern (vm ist null, weil es auf einige Daten in der realen App wartet)

+0

Natürlich, weil es keine Benachrichtigung, die Ansichtsmodell geändert hat –

+0

Sie meinen ViewModel-Eigenschaft? Wie kann ich über Änderung benachrichtigen - ich möchte INotifyPropertychange in MainPage nicht implementieren – Alamakanambra

+0

Ohne Magie mussten Sie die Seite benachrichtigen, dass der Inhalt von ViewModel geändert hat. Es spielt keine Rolle, wie Sie es tun, aber Sie müssen –

Antwort

0

Haben Sie INotifyPropertyChanged auf Seite implementieren wie so

public sealed partial class MainPage : Page, INotifyPropertyChanged 
{ 
    private ViewModel viewModel; 

    public ViewModel ViewModel 
    { 
     get { return viewModel; } 
     set 
     { 
      viewModel = value; 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ViewModel))); 
     } 
    } 

    public MainPage() 
    { 
     ViewModel = new ViewModel { }; 
     this.InitializeComponent(); 
    } 

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
    { 
     ViewModel = new ViewModel { };//this line has been added 
     ViewModel.Text = "x:Bind does not work"; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

Dies funktioniert für mich.

1

{x: Bindung} Bindungen (oft als kompilierte Bindungen bezeichnet) verwendet generierten Code, um seine Vorteile zu erzielen. Bei der XAML-Ladezeit wird {x: Bind} in das umgewandelt, was Sie sich als Bindungsobjekt vorstellen können, und dieses Objekt erhält einen Wert aus einer Eigenschaft einer Datenquelle. Dieser generierten Code in Ihren obj Ordnern gefunden werden, mit Namen wie (für C#) <view name>.g.cs.

für Ihren Code, wird der generierte Code folgende mag:

// Update methods for each path node used in binding steps. 
private void Update_(global::UWP.BlankPage3 obj, int phase) 
{ 
    if (obj != null) 
    { 
     if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0) 
     { 
      this.Update_ViewModel(obj.ViewModel, phase); 
     } 
    } 
} 
private void Update_ViewModel(global::UWP.ViewModel obj, int phase) 
{ 
    this.bindingsTracking.UpdateChildListeners_ViewModel(obj); 
    if (obj != null) 
    { 
     if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0) 
     { 
      this.Update_ViewModel_Text(obj.Text, phase); 
     } 
    } 
} 

... 

private global::UWP.ViewModel cache_ViewModel = null; 
public void UpdateChildListeners_ViewModel(global::UWP.ViewModel obj) 
{ 
    if (obj != cache_ViewModel) 
    { 
     if (cache_ViewModel != null) 
     { 
      ((global::System.ComponentModel.INotifyPropertyChanged)cache_ViewModel).PropertyChanged -= PropertyChanged_ViewModel; 
      cache_ViewModel = null; 
     } 
     if (obj != null) 
     { 
      cache_ViewModel = obj; 
      ((global::System.ComponentModel.INotifyPropertyChanged)obj).PropertyChanged += PropertyChanged_ViewModel; 
     } 
    } 
} 

Hier kopiere ich nur eine Methode, die zu Ihrem Problem im Zusammenhang. Von diesen Methoden können Sie feststellen, dass vor dem Update TextBlock oder PropertyChanged Zuhörer überprüft wird, ob ViewModelnull ist. Wenn es null ist, wird nichts getan werden. Um {x: Bind} arbeiten zu lassen, müssen wir ViewModel vor dem Laden der Seite initialisieren. Und das ist der Grund, warum {x: Bind} nicht funktioniert, wenn Sie ViewModel in Button.Click Ereignis initialisieren.

um dieses Problem zu beheben, Sie INotifyPropertyChanged Schnittstelle für ViewModel implementieren können wie Filip sagte, so dass der generierte Code mitgeteilt werden kann, wenn ViewModel (von null zu new ViewModel()) geändert, und Sie UI aktualisieren.

Aber ich denke, Sie können ViewModel im Konstruktor gerade initialisieren. Wenn Sie ViewModel initialisieren, können Sie die Eigenschaften festgelegt, die Sie wie zu null warten zuerst:

public MainPage() 
{ 
    ViewModel = new ViewModel() { Text = null }; 
    this.InitializeComponent(); 
} 

Und dann diese Eigenschaften aktualisieren, wenn Sie das Datum bereit ist. Auf diese Weise können Sie die Schnittstelle INotifyPropertyChanged nicht auf Ihrer Seite implementieren.

Daneben gibt es eine andere billigere Art und Weise, können Sie this.Bindings.Update(); Methode aufrufen, die Bindungen aktualisiert werden zu erzwingen, nachdem Sie ViewModel initialisieren wie folgt vor:

private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
{ 
    ViewModel = new ViewModel(); 
    ViewModel.Text = "x:Bind does not work"; 
    this.Bindings.Update(); 
}