Respect of MVVM w/o any framework

Umar3xUmar3x FRMember ✭✭
edited October 3 in Xamarin.Forms

Hello all,

I'm working on an application for which the map is the central element (I'd like to say an uber app like).

I've been implementing a lot of animation to get a beautiful app and so I got an Animation service that hold method to animates objects through DI in specific flows.

But as I'm new in xamarin (8 months working on it) I did not start the project with any frameworks, nor MVVM light or FreshMVVM and I think, correct me if I'm wrong that its too late for thinking of integrating one of those fmks in this project.

I'm using TKCustomMap and MR.Gestures packages , last one providing command binding on multiple controls, which is great.

What I want to know:

I got a IsInNavigationMode property in the view model which is set to true when the route calculation finished. TKCustomMap provides a command for that which is RouteCalculationFinishedCommand.

     /// <summary>
        /// Command when a route calculation finished
        /// </summary>
        public Command<TKRoute> RouteCalculationFinishedCommand
        {
            get
            {
                return new Command<TKRoute>(async r =>
                {
                    // move to the bounds of the route
                    this.MapRegion = r.Bounds;
                    //await PopupNavigation.PushAsync(new RoutesInstructionPage(r, this), true);
                    await LoadingService.EndLoading(200);
                    IsInNavigationMode = true;
                });
            }
        }

Right.
As far as I know if I want my view to be aware of changes in viewModel I need to create a bindable propertie on my Map object IsInNavigationModeProperty and binding it to the property of the viewModel using binding.mode twoWay.

VM : 
        /// <summary>
        /// Bool to determine if user is navigate 
        /// </summary>
        public bool IsInNavigationMode
        {
            get => _isInNavigationMode;
            set
            {
                if (_isInNavigationMode == value) return;
                _isInNavigationMode = value;
                OnPropertyChanged("IsInNavigationMode");
            }
        }

Map :

   ` public static readonly BindableProperty IsInNavigationModeProperty = BindableProperty.Create("IsInNavigationMode", typeof(bool), typeof(CustomMap), false, BindingMode.TwoWay);`

And here is where Im stuck.

When the property changes in view or viewModel I want to call my service to animate components (as some of them need to disappear when in navigationMode or appear when NOT).

I got a Wrapper component that hold other components that need to be or not animated (I need animation not just displaying or not).
I know that I should go through command for that but I only see example with gesture recognization (like MR.Gestures) for a button or other controls but not for a bool property that would change and call from these change the good animation method by passing my wrapper as a commandParameter but not thanks to any user interaction/event such as click. I'd like to keep my MapPage with the less possible handlers and w/o directs interactions between my view and viewModel to respect MVVM.

So I did an ugly thing, working but ugly, I think, that's where I'm lost, I'm not sure that what I do is safe, good, and not readable and maintainable and I feel there is something wrong in my approach.

MapViewModel.PropertyChanged += async (sender, e) =>
    {
        if(e.propertyName == "IsInNavigationMode")
    {
    if(MapViewModel.IsInNavigationMode)
              {
        await AnimationService.SetMapComponentsWhenOnNavigationMode(new WrapperMapComponents(_bottomMapMenuComponents, _pinOptionComponents, _addActionComponents));
                }
           else
               {
                    await AnimationService.SetMapComponentsWhenOffNavigationMode(new WrapperMapComponents(_bottomMapMenuComponents, _pinOptionComponents));
                }
    }
    }

I've shortered the code to make it clearer
Hope I've been clear enough. Thanks to anyone taking time to read and/or help

Tagged:

Posts

  • MulflarMulflar ESUniversity ✭✭
    edited October 3

    What about:

        public bool IsInNavigationMode
        {
            get => _isInNavigationMode;
            set
            {
                if (_isInNavigationMode == value) return;
                _isInNavigationMode = value;
            if(isInNavigationMode)
               {
                    await AnimationService.SetMapComponentsWhenOnNavigationMode(new WrapperMapComponents(_bottomMapMenuComponents, _pinOptionComponents, _addActionComponents));
                }
               else
               {
                    await AnimationService.SetMapComponentsWhenOffNavigationMode(new WrapperMapComponents(_bottomMapMenuComponents, _pinOptionComponents));
                }
                OnPropertyChanged("IsInNavigationMode");
            }
        }
    

    That's only the concept, you should move the awaits to funcions and call the functions in the property

  • Umar3xUmar3x FRMember ✭✭
    edited October 3

    Hello @Mulflar

    Thanks for you answer. But the prob in what you propose is that arguments passed to the wrapper are not known by the viewmodel as I initialize them in the view and add them to a grid. How can I pass them to the vm then w/o command ?

    Here is my bottomMapMenuComponents class :

      public class BottomMapMenuComponents
        {
            public MR.Gestures.StackLayout MainFlowLayout;
            public MR.Gestures.StackLayout FirstFlowLayout;
            public MR.Gestures.StackLayout SecondFlowLayout;
            public MR.Gestures.StackLayout ThirdFlowLayout;
            public MR.Gestures.Label FirstFlowActionLabel;
            public MR.Gestures.Label SecondFlowActionLabel;
            public MR.Gestures.Label ThirdActionLabel;
    
          /// <summary>
          /// 
          /// </summary>
          public BottomMapMenuComponents()
           { 
              //The layout that holds the bottom buttons
               MainFlowLayout = new MR.Gestures.StackLayout
                {
                   Orientation = StackOrientation.Horizontal,
                    BackgroundColor = Color.FromHex("#2E383F"),
                    VerticalOptions = LayoutOptions.End,
                    HorizontalOptions = LayoutOptions.FillAndExpand
                 }; 
    
            ... and other components init
            }
    
  • Umar3xUmar3x FRMember ✭✭
    edited October 3

    failed.

  • MulflarMulflar ESUniversity ✭✭

    Mmm... My first Idea is ever try to move all to the viewmodel, but if you don't/can't do it the other option could be using Messaging Center.
    You subscribe the view to a message who activates the animation, and another one who desactivate the animation (remember to unsuscribe it).
    Then in the viewmodel when the prop setter is fired you send a message to the view.

    Here you can get more info:
    https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/messaging-center/

  • Umar3xUmar3x FRMember ✭✭
    edited October 3

    Well @Mulflar I'm going to use the messaging Center then. Thanks for your advise.

    Last question : When should I unsuscribe (more efficient ?). What I mean is that I don't even really want to unsubscribe as as far as the user is on the map, I shoud always listen to these properties changes.

  • MulflarMulflar ESUniversity ✭✭

    If you subscribe to messaging each time you see the screen, you should unsuscribe each time you go out. If not you would duplicate the effect.
    Implement the subscription and test change screens (if have), and sleep, stop, resume etc to see if in some cases the messaging is called more than once each time.

  • Umar3xUmar3x FRMember ✭✭

    Okay, I'll investigatate more in case but I think everything's working fine. Thanks a lot, I'd like to mark your post as "the answer" but can't find where on this forum :'(

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @Umar3x said:
    Okay, I'll investigatate more in case but I think everything's working fine. Thanks a lot, I'd like to mark your post as "the answer" but can't find where on this forum :'(

    Did you start the thread as a QUESTION or a DISCUSSION? If it is a discussion there is no right answer.

  • 15mgm1515mgm15 USMember ✭✭✭

    I am interested in this, there may be parts of the development process where you can easily break the pattern, It will be a good idea to investigate further.

Sign In or Register to comment.