Issue with MVVM and BindableProperties.

nicktheonenicktheone Member ✭✭

I'm very new to MVVM and Xamarin in general and I'm sure I'm going to ask a stupid question but still...

One of my views is used right now to display (among other things) a clock that resided in a BindableProperty EorzeaTimeNow bound in the XAML to a Label text like so:

CODE BEHIND:

namespace Eorzea_Gatherer.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class HomeView : ContentPage
    {
        #region BindableProperty
        public static readonly BindableProperty EorzeaTimeNowProperty = BindableProperty.Create(
            nameof(EorzeaTimeNow),
            typeof(DateTime),
            typeof(HomeView),
            default(DateTime));

        public DateTime EorzeaTimeNow
        {
            get => (DateTime)GetValue(EorzeaTimeNowProperty);
            set => SetValue(EorzeaTimeNowProperty, value);
        }
        #endregion

        public HomeView()
        {
            InitializeComponent();

            //Start the timer that calculates Eorzea Time
            Device.StartTimer(TimeSpan.FromMilliseconds(1000), () =>
            {
                DateTime eorzeaTime = DateTime.Now.ToEorzeaTime();

                //Create a fake date and assign to it the hour and the minute of the day
                DateTime fakeEorzeaTime = new DateTime(1970, 1, 1, eorzeaTime.Hour, eorzeaTime.Minute, 0);
                EorzeaTimeNow = fakeEorzeaTime;

                return true;
            });
        }
    }
}

XAML:

<Label Text="{Binding EorzeaTimeNow, StringFormat='{}{0:hh:mm}', Source={x:Reference MyHomeView}}"
                       TextColor="#171717"
                       FontFamily="Gilroy-Light"
                       HorizontalOptions="Center">
                    <Label.FontSize>
                        <OnIdiom x:TypeArguments="x:Double" Phone="37" Tablet="71"/>
                    </Label.FontSize>
                </Label>

What I'm trying to accomplish is moving said BindableProperty to my ViewModel like so:

namespace Eorzea_Gatherer.ViewModels
{
    public class HomeViewModel : BindableObject
    {
        public static readonly BindableProperty EorzeaTimeNowProperty = BindableProperty.Create(
            nameof(EorzeaTimeNow),
            typeof(DateTime),
            typeof(HomeView),
            default(DateTime));

        public DateTime EorzeaTimeNow
        {
            get => (DateTime)GetValue(EorzeaTimeNowProperty);
            set => SetValue(EorzeaTimeNowProperty, value);
        }
    }
}

but when I try to access it like HomeViewModel.EorzeaTimeNow = fakeEorzeaTime; I get an error stating "An object reference is required for the non-static field, method or property".

Now, my question is: what I'm trying to do does even make sense? Is there any better approach to it?

Best Answer

  • LucasZhangLucasZhang Xamurai
    Accepted Answer

    Though you used MVVM ,you don't need to set the binding cource again in xaml

    Source={x:Reference MyHomeView}
    

    Refer the following code

    in xaml

    <Label Text="{Binding EorzeaTimeNow, StringFormat='{}{0:hh:mm}' }"
                           TextColor="#171717"
                           FontFamily="Gilroy-Light"
                           HorizontalOptions="Center">
                        <Label.FontSize>
                            <OnIdiom x:TypeArguments="x:Double" Phone="37" Tablet="71"/>
                        </Label.FontSize>
    </Label>
    

    code behind

    public HomeView()
    {
        InitializeComponent();
    
        BindingContext = new HomeViewModel();
    }
    

    in ViewModel

    public class HomeViewModel : BindableObject
        {
            public static readonly BindableProperty EorzeaTimeNowProperty = BindableProperty.Create(
                nameof(EorzeaTimeNow),
                typeof(DateTime),
                typeof(MainPage),
                default(DateTime));
    
            public DateTime EorzeaTimeNow
            {
                get => (DateTime)GetValue(EorzeaTimeNowProperty);
                set => SetValue(EorzeaTimeNowProperty, value);
            }
    
            public HomeViewModel()
            {
                EorzeaTimeNow = new DateTime();
    
                Device.StartTimer(TimeSpan.FromMilliseconds(1000), () =>
                {
                    DateTime eorzeaTime = DateTime.Now.ToEorzeaTime();
    
                    //Create a fake date and assign to it the hour and the minute of the day
                    DateTime fakeEorzeaTime = new DateTime(1970, 1, 1, eorzeaTime.Hour, eorzeaTime.Minute, 0);
                    EorzeaTimeNow = fakeEorzeaTime;
    
                    return true;
                });
            }
    
        }
    

Answers

  • LucasZhangLucasZhang Member, Xamarin Team Xamurai
    Accepted Answer

    Though you used MVVM ,you don't need to set the binding cource again in xaml

    Source={x:Reference MyHomeView}
    

    Refer the following code

    in xaml

    <Label Text="{Binding EorzeaTimeNow, StringFormat='{}{0:hh:mm}' }"
                           TextColor="#171717"
                           FontFamily="Gilroy-Light"
                           HorizontalOptions="Center">
                        <Label.FontSize>
                            <OnIdiom x:TypeArguments="x:Double" Phone="37" Tablet="71"/>
                        </Label.FontSize>
    </Label>
    

    code behind

    public HomeView()
    {
        InitializeComponent();
    
        BindingContext = new HomeViewModel();
    }
    

    in ViewModel

    public class HomeViewModel : BindableObject
        {
            public static readonly BindableProperty EorzeaTimeNowProperty = BindableProperty.Create(
                nameof(EorzeaTimeNow),
                typeof(DateTime),
                typeof(MainPage),
                default(DateTime));
    
            public DateTime EorzeaTimeNow
            {
                get => (DateTime)GetValue(EorzeaTimeNowProperty);
                set => SetValue(EorzeaTimeNowProperty, value);
            }
    
            public HomeViewModel()
            {
                EorzeaTimeNow = new DateTime();
    
                Device.StartTimer(TimeSpan.FromMilliseconds(1000), () =>
                {
                    DateTime eorzeaTime = DateTime.Now.ToEorzeaTime();
    
                    //Create a fake date and assign to it the hour and the minute of the day
                    DateTime fakeEorzeaTime = new DateTime(1970, 1, 1, eorzeaTime.Hour, eorzeaTime.Minute, 0);
                    EorzeaTimeNow = fakeEorzeaTime;
    
                    return true;
                });
            }
    
        }
    
  • nicktheonenicktheone Member ✭✭

    Thanks! Much appreciated. Do you, perchance, have any resources with examples for someone starting now with MVVM? Particularly I think I have a relatively solid idea about the whole paradigm but maybe some more examples could help me.

Sign In or Register to comment.