Benutzer mit den meisten Antworten
INotifyPropertyChanged update value in mehreren UserControls

Frage
-
Wie ist es möglich über InotifyPropertyChanged einen Wert in mehreren Usercontrols zu aktualisieren?
Mein Projekt umfasst ein MainPage die zwei weitere UserContrlos beinhallten. Alle drei Controlls haben das Selbe Binding an eine TextBox mit je einem einem Button der Click bar ist.Klicke ich nun auf einen Butten in einem Control so ändert sich nur der Text in der TextBox der im selben Control ist obschon die beiden andren Controls das selbe Binding haben. Also die Anderen Controls bekommen von dem Click respektive des neuen DataContextes nicht mit.
Wie teile ich den Beiden anderen Controls mit, wenn ein Button geClickt wurde das sich nun der DataContext geändert hat?
Interessanterweise, habe ein Beispiel gefunden das die Uhrzeit jede sec aktualisiert und dies wird in allen 3 Controls aktualisiert...!?
Grüsse JanLeu
Donnerstag, 11. Oktober 2012 19:10
Antworten
-
Hi,ich habe mir Deinen Code mal angeschaut.Die von Dir gewünschte “zentrale Zustandsverwaltung” erfordert, dass alle Bindungen das gleiche Objekt nutzen. In Deinem Fall erzeugst Du überall neue Objekte, die dann natürlich auch nur dort wirken, wo sie gebunden sind. Dabei ist es ohne Bedeutung, dass die Verweisvariablen die gleiche Bezeichnung haben. Da diese aber in unterschiedlichen Bereichen (Skopes) gültig sind, haben sie miteinander nichts zu tun.Damit alle Steuerelemente synchron anzeigen, müssen sie für die Bindung dasselbe Objekt nutzen. Die Objektinstanz kann man in diesem Fall am einfachsten in der App.xaml erzeugen, z.B. so:<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"x:Class="SilverlightApplication1.App"xmlns:UserControls="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1"><Application.Resources><UserControls:ButtonClickCommandBindingViewModal x:Key="vm" /></Application.Resources></Application>In allen andern Moduln wird dann der Schlüssel “vm” für den DataContext genutzt, z.B. deklarativ so:<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource vm}}">Du kannst natürlich auch im Code binden. Ich liebe aber MVVM und da braucht man keinen Code für die Bindung.Die Änderung einer Eigenschaft im gebundenen ViewModel kann dann beispielsweise so aussehenin VB.NET:CType(Application.Current.Resources("vm"), ButtonClickCommandBindingViewModal).Text = "Button Right Clicket"bzw. in C#.NET:(ButtonClickCommandBindingViewModal)Application.Current.Resources["vm"]).Text = "Button Right Clicket";--
Viele Gruesse
Peter- Als Antwort vorgeschlagen Peter Fleischer Samstag, 13. Oktober 2012 04:24
- Als Antwort markiert JanLeu Samstag, 13. Oktober 2012 12:24
Samstag, 13. Oktober 2012 04:20
Alle Antworten
-
Wenn dasselbe Objekt, welches INotifyPropertyChanged auslöst, an verschiedene Steuerelemente gebunden ist, dann bekommen diese Steuerelemente das auch mit. Wenn diese Bindung aber nicht direkt ist, sondert beispielsweise an eine DependencyProperty des UserControls, so muss PropertyChanged abgefangen und weitergeleitet werden.--
Viele Gruesse
PeterDonnerstag, 11. Oktober 2012 20:19 -
Hallo Peter
Das DependencyProperty habe ich in meinem Projekt nicht verwendet. Habe aber bereits mit dem Gedanken gespielt es zu verwenden da ich gelesen habe das es Propertys gegen aussen zu Verfügung stellt und so der Ansatz für mein Problemlösung sein könnte.
Ich möchte hier kurz mein Code zeigen…
die MainPage.xaml
<UserControl.Resources> <ViewModel:RefreshingClock x:Key="Clock" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="70"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBox Height="30" Grid.Column="0" Grid.Row="0" Background="AliceBlue" HorizontalAlignment="Center" x:Name="textBlock1" Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" VerticalAlignment="Top" Width="217" /> <TextBox Height="30" Grid.Column="0" Grid.Row="0" Background="AliceBlue" HorizontalAlignment="Center" x:Name="textBlock2" Text="{Binding Path=Text}" VerticalAlignment="Bottom" Width="217" /> <Button Grid.Column="1" Grid.Row="0" Width="150" Height="30" Content="Button Main Page" VerticalAlignment="Top" x:Name="btnMainPage" Click="BtnMainPageClick" /> <TextBlock Text="{Binding Path=CurrentTime, Source={StaticResource Clock}}" VerticalAlignment="Bottom" Grid.Column="1" Grid.Row="0" /> <StackPanel Grid.Column="0" Grid.Row="1" Margin="10"> <UserControls:ControlL HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> </StackPanel> <StackPanel Grid.Column="1" Grid.Row="1" Margin="10"> <UserControls:ControlR HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> </StackPanel> </Grid>
der Code
public partial class MainPage : UserControl { public ButtonClickCommandBindingViewModal Data; public MainPage() { InitializeComponent(); Data = new ButtonClickCommandBindingViewModal(); this.DataContext = Data; } private void BtnMainPageClick(object sender, RoutedEventArgs e) { //Data.Text = "Button Main Page Clicket"; Data = new ButtonClickCommandBindingViewModal { Text = "Button Main Page Clicket" }; this.DataContext = Data; } }
Ein UserControl
<UserControl.Resources> <ViewModel:RefreshingClock x:Key="Clock" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="#FFF29999" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Grid.RowDefinitions> <RowDefinition Height="50"></RowDefinition> <RowDefinition Height="50"></RowDefinition> <RowDefinition Height="50"></RowDefinition> </Grid.RowDefinitions> <TextBox Height="30" Grid.Row="0" Background="AliceBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Name="textBlock1" Text="{Binding Path=Text}" Width="217"/> <Button x:Name="btnButtonLinks" Grid.Row="1" Width="150" Height="30" Content="ButtonLinks" Click="BtnButtonLinksClick" /> <TextBlock Text="{Binding Path=CurrentTime, Source={StaticResource Clock}}" Grid.Row="2" /> </Grid>
Der Code
public partial class ControlL : UserControl { public ButtonClickCommandBindingViewModal Data; public ControlL() { InitializeComponent(); Data = new ButtonClickCommandBindingViewModal(); this.DataContext = Data; } private void BtnButtonLinksClick(object sender, RoutedEventArgs e) { Data.Text = "Button Left Clicket"; DataContext = Data; } }
Die Classe dazu
public class ButtonClickCommandBindingViewModal : INotifyPropertyChanged { private string _text; public string Text { get { return _text; } set { _text = value; NotifyPropertyChanged("Text"); } } protected void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion }
Beim Debugen kann ich verfolgen, dass ProppertyChanged ausgeführt wird.
Habe schon versucht das Binding über UserControl.Resources abzuwickeln so wie bei der Uhr die richtig Tickt und alle Controls aktualisiert.
Danke & Grüsse
JanLeu
Freitag, 12. Oktober 2012 05:30 -
Hi,ich habe mir Deinen Code mal angeschaut.Die von Dir gewünschte “zentrale Zustandsverwaltung” erfordert, dass alle Bindungen das gleiche Objekt nutzen. In Deinem Fall erzeugst Du überall neue Objekte, die dann natürlich auch nur dort wirken, wo sie gebunden sind. Dabei ist es ohne Bedeutung, dass die Verweisvariablen die gleiche Bezeichnung haben. Da diese aber in unterschiedlichen Bereichen (Skopes) gültig sind, haben sie miteinander nichts zu tun.Damit alle Steuerelemente synchron anzeigen, müssen sie für die Bindung dasselbe Objekt nutzen. Die Objektinstanz kann man in diesem Fall am einfachsten in der App.xaml erzeugen, z.B. so:<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"x:Class="SilverlightApplication1.App"xmlns:UserControls="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1"><Application.Resources><UserControls:ButtonClickCommandBindingViewModal x:Key="vm" /></Application.Resources></Application>In allen andern Moduln wird dann der Schlüssel “vm” für den DataContext genutzt, z.B. deklarativ so:<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource vm}}">Du kannst natürlich auch im Code binden. Ich liebe aber MVVM und da braucht man keinen Code für die Bindung.Die Änderung einer Eigenschaft im gebundenen ViewModel kann dann beispielsweise so aussehenin VB.NET:CType(Application.Current.Resources("vm"), ButtonClickCommandBindingViewModal).Text = "Button Right Clicket"bzw. in C#.NET:(ButtonClickCommandBindingViewModal)Application.Current.Resources["vm"]).Text = "Button Right Clicket";--
Viele Gruesse
Peter- Als Antwort vorgeschlagen Peter Fleischer Samstag, 13. Oktober 2012 04:24
- Als Antwort markiert JanLeu Samstag, 13. Oktober 2012 12:24
Samstag, 13. Oktober 2012 04:20 -
Hallo Peter
Genau, nach dem Lesen deiner Erklärung fällt es mir wie Schuppen von den Augen. Auf die Idee der einzeln
Initialisierten Objekte wäre ich alleine wohl noch lange nicht gekommen!!!Danke dass du dir die Zeit genommen hast. Du hast mir sehr geholfen die zusammenhänge klarer zu sehen!
Das kleine übungs- Projekt funktioniert nun einwandfrei!Grüsse JanLeu
Samstag, 13. Oktober 2012 12:25