0
votes

Desired Result

  • A status bar at the top of most xaml pages, of which the colour and text change depending on the value of a boolean variable.
  • The page background is also set to a colour based on this boolean.
  • Essentially these signify whether the app is connected to the server; we don't need to discuss connectivity logic here, apart from a method which inverts the "online" boolean, so as to simulate changing connectivity status and to test the bindings.
  • I want these to update without repeated logic in every view model.

Current Implementation

To try and minimise the amount of code, I will try to reduce the project into four files, and also only concern ourselves with the text property (if we can get text working, we can get colour working too). Hopefully we can assume my ViewModelLocator.cs, App.xaml, Generic.xaml and the supporting ConnectivityStatusBar.cs have been correctly implemented (I can share these too if necessary).

  • HomePage.xaml: An example view which utilises the connectivity status bar.
<Page
    x:Class="Client.View.HomePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:customElements="using:Client.CustomElements"
    mc:Ignorable="d"
    DataContext="{Binding Source={StaticResource ViewModelLocator}}">

    <Grid>
        <StackPanel>
            <customElements:ConnectivityStatusBar
                Text="{Binding ConnectivityStatusBar.Text,
                      Source={StaticResource ViewModelLocator}}" />
            <Button Content="Invert"
                    Command="{Binding HomePage.InvertConnectivityCommand}" />
        </StackPanel>
    </Grid>
</Page>
  • SessionData.cs: Where the connectivity boolean is found, I have tried setting the class up like a singleton.
using Client.ViewModel;
using GalaSoft.MvvmLight;

namespace Client
{
    public sealed class SessionData : ViewModelBase
    {
        private static readonly SessionData Instance = new SessionData();
        private bool _online;

        public static SessionData getInstance
        {
            get { return Instance; }
        }

        public bool Online
        {
            get { return _online; }
            set
            {
                _online = value;
                RaisePropertyChanged(() => Online);
                RaisePropertyChanged(() => ConnectivityStatusBarViewModel.getInstance.Text);
            }
        }
    }
}
  • ConnectivityStatusBarViewModel.cs: Logic deciding what the colour and text for the status bar should be. I have attempted similar singleton logic here.
using System;
using GalaSoft.MvvmLight;

namespace Client.ViewModel
{
    public sealed class ConnectivityStatusBarViewModel : ViewModelBase
    {
        private static readonly ConnectivityStatusBarViewModel Instance = new ConnectivityStatusBarViewModel();

        public static ConnectivityStatusBarViewModel getInstance
        {
            get { return Instance; }
        }

        public String Text
        {
            get { return SessionData.getInstance.Online ? "Online" : "Offline"; }
        }
    }
}
  • HomePageViewModel.cs: Where the boolean inversion method is found.
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace Client.ViewModel
{
    public class HomePageViewModel : ViewModelBase
    {
        public HomePageViewModel()
        {
            InvertConnectivityCommand = new RelayCommand(InvertConnectivity);
        }

        public RelayCommand InvertConnectivityCommand { get; set; }

        private void InvertConnectivity()
        {
            SessionData.getInstance.Online = !SessionData.getInstance.Online;
        }
    }
}

This code doesn't give me the results I want; when the button is pressed on HomePage.xaml, the text does not change. It does work if I put the inversion method into ConnectivityStatusBarViewModel.cs.

Is it possible to make this work, or am I wasting my time? If it is possible, how can I change my approach to make it work?

Edit: ViewModelLocator.cs looks like:

using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;

namespace Client.ViewModel
{
    public class ViewModelLocator
    {
        static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<ConnectivityStatusBarViewModel>();
            SimpleIoc.Default.Register<HomePageViewModel>();
        }

        public ConnectivityStatusBarViewModel ConnectivityStatusBar
        {
            get { return ServiceLocator.Current.GetInstance<ConnectivityStatusBarViewModel>(); }
        }

        public HomePageViewModel HomePage
        {
            get { return ServiceLocator.Current.GetInstance<HomePageViewModel>(); }
        }
    }
}
1
What does it mean that it doesn't work? The command is not invoked? Are you getting any binding errors in the Output window?Igor Ralic
If I debug the InvertConnectivity(), I can see that it is invoked. The Online boolean and Text string are both changed if I output them, however the actual text on screen does not change.Matthew Fitch
Have you tried binding to ConnectivityStatusBarViewModel.getInstance.Text? Or is the ConnectivityStatusBar already returning ConnectivityStatusBar.getInstance in the VMLocator?Igor Ralic
I'm not sure how to do that, I have included the VMLocator code if that helps.Matthew Fitch

1 Answers

0
votes

Instead of registering new ConnectivityStatusBarViewModel instance in ViewModelLocator, can you try providing the exact instance to it.

SimpleIoc.Default.Register(() => ConnectivityStatusBarViewModel.getInstance);

This way when the call to get the instance gets invoked:

return ServiceLocator.Current.GetInstance<ConnectivityStatusBarViewModel>();

you will actually be returning that instance.

So when you do binding to VMlocator and ConnectivityStatusBar.Text, it should work.

Text="{Binding ConnectivityStatusBar.Text,
       Source={StaticResource ViewModelLocator}}" 

You were essentially binding to another instance, which is why the data wasn't refreshed in the UI.

BTW there are some design issues/redundancies with this/your code, but it's out of the scope of the question - I am trying to make minimal changes to it to get it working.