I want to update my UI, but it didn't get updated, even when the PropertyChanged
event got called. At startup i get the first values, but after changes it won't update.
While Debugging, i can see, that the values getting updated and the PropertyChanged
event got fired, but the getter didn't get called.
(BTW: I'm relatively new to C#, respectively to the M-V-VM concept.)
XAML
<Page.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
...
<TextBlock x:Name="LatitudeVar" Text="{Binding LatitudeVar, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="79" Canvas.Left="189" Canvas.Top="38" />
C# (MainPageViewModel)
public class MainPageViewModel : ViewModelBase, INotifyPropertyChanged
{
private Session _session;
public MainPageViewModel()
{
_session = Session.Instance;
}
public static readonly MainPageViewModel Instance = new MainPageViewModel();
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
{
// App just started, so we get GPS access and eventually initialize the client
Session.InitializeClient();
await StartGpsDataService();
await Task.CompletedTask;
}
...
private string _latitude;
public string LatitudeVar
{
get { return _session.Latitude; }
set { _session.Latitude = value; NotifyPropertyChanged(); }
}
...
public async Task StartGpsDataService()
{
await Session.InitializeDataUpdate();
}
public new event PropertyChangedEventHandler PropertyChanged;
[Annotations.NotifyPropertyChangedInvocator]
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
C# (Session)
public class Session : INotifyPropertyChanged
{
public static void InitializeClient()
{
MainPageViewModel mpvm = new MainPageViewModel();
_mpvm = MainPageViewModel.Instance;
}
private static Session _instance;
public static Session Instance
{
get
{
if (_instance == null)
{
_instance = new Session();
}
return _instance;
}
}
private static Session _sc;
internal static Session Sc
{
get { return _sc; }
set { _sc = value; }
}
private static MainPageViewModel _mpvm;
private string _latitude;
public string Latitude
{
get { return _latitude; }
set
{
if (_latitude == value) return; _latitude = value; RaiseOnPropertyChanged("Latitude"); }
}
...
public void UpdateGpsData(Geopoint point, Geopoint geopointOld)
{
_mpvm.LatitudeVar = point.Position.Latitude.ToString();
}
public static async Task InitializeDataUpdate()
{
Sc = Session.Instance;
Sc.StartTime = DateTime.Now;
Sc.GetPosition(Geoposition.Coordinate.Point);
}
public new event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void RaiseOnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Some ways i tried before:
C# (MainPageViewModel)
private string _latitude;
public string LatitudeVar
{
get { return _latitude; }
set { _latitude = value; NotifyPropertyChanged("LatitudeVar"); }
}
Result: Values were not displayed.
C# (Session)
public void UpdateGpsData(Geopoint point, Geopoint geopointOld)
{
Latitude = point.Position.Latitude.ToString();
}
Result: Values were diplayed at startup, but not updated.
EDIT: Found a solution: Some code sorting, thanks for the hint ;) Now my Session.cs is a Model. All relavant methods are now in the ViewModel. And i took care of, that only one instance exists:
public MainPageViewModel()
{
_session = Session.Instance;
_instance = this;
}
Woah, that's quite a contrived singleton pattern implementation.
Firstly, the MainPageViewModel instance created in Session.InitializeClient is not the instance that is being used by the view. The XAML
<Page.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
Will instantiate a new instance of MainPageViewModel so the code
public void UpdateGpsData(Geopoint point, Geopoint geopointOld)
{
_mpvm.LatitudeVar = point.Position.Latitude.ToString();
}
Will have no effect on the view.
While I would strongly encourage you to remove the attempt at a singleton for the Session and consider using a messaging pattern to communicate between system components, you should be able to get your code working by exposing the Session instance singleton as a readonly property on the MainPageViewModel and binding to that directly as follows:
<TextBlock Text="{Binding Path=Session.Latitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Of course, this then means your UI is writing directly to a singleton component in your system in which it's probably not desirable to implement INotifyPropertyChanged.
As suggested, I'd strongly recommend rearchitecting and removing the singleton and/or embracing messaging between system components.