Prism Inheriting from ViewModelBase vs BindableBase - xamarin.forms

When I create a new Xamarin.Forms application using the Prism template pack the project gets created with a MainPageViewModel that inherits from ViewModelBase
Later I create and an additional View and ViewModel say for ChatPage. This ChatPageViewModelinherits from BindableBasenot ViewModelBase as generated by the Add New dialog.
I'd like to use ViewModelBase in all my View(Models) ViewModelBase inherits from ViewModelBase : BindableBase, INavigationAware, IDestructible
I try and change the new ChatPageViewModel : BindableBase to ChatPageViewModel : ViewModelBase but the constructor gets a red squiggly error;
Error CS7036 There is no argument given that corresponds to the required formal parameter 'navigationService' of 'ViewModelBase.ViewModelBase(INavigationService)'
I see in App.xaml.cs that containerRegistry.RegisterForNavigation<NavigationPage>(); is implemented differently than the other pages containerRegistry.RegisterForNavigation<ChatPage, ChatPageViewModel>();
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<MainPage, MainPageViewModel>();
containerRegistry.RegisterForNavigation<SettingsPage, SettingsPageViewModel>();
containerRegistry.RegisterForNavigation<ChatPage, ChatPageViewModel>();
containerRegistry.RegisterSingleton<IXpdSettings, XpdSettings>();
containerRegistry.RegisterSingleton<IMqttDataService, MqttDataService>();
}
Is there a way I can inherit from ViewModelBase? Could / should it be implemented in the XamarinForms Prism templating?

The answer is contained in my question. See the syntax that the MainPageViewModel (that was created by the initial project creation dialog) uses - where MainPageViewModel inherits from ViewModelBase unlike subsequent pages created with Add New dialog that inherit from BindableBase. For instance ChatPageViewModel inheriting from ViewModelBase rather than BindableBase.
public class ChatPageViewModel : ViewModelBase
{
private IXpdSettings _xpdsettings;
public ChatPageViewModel(INavigationService navigationService, IXpdSettings xpdSettings)
: base(navigationService)
{
Title = "Mqtt Chat";
_xpdsettings = xpdSettings;
}
}

Related

How to use BindableProberty directly inside ViewModelBase class from MVVMHelper

i think my problem is about misunderstanding OOP, when my class inherits BindableObject my code is working fine , but when my Class inherits MVVMhelper ViewModelBase the SetValue and GetValue is not defined in the current context,but i need to use bindable property in my view model
public class TestViewModel : ViewModelBase
{
public TestViewModel()
{
}
public static readonly BindableProperty IsWorkingProperty =
BindableProperty.Create(nameof(IsWorking), typeof(bool),
typeof(TestViewModel), default(bool));
public bool IsWorking
{
get { return (bool)GetValue(IsWorkingProperty); }
set { SetValue(IsWorkingProperty, value); }
}
}
ViewModelBase is mvvm helper base view model which inherits from inotifypropertychanged, i say when i replase viewmodelbase with bindableobject every thing is working
you said that ViewModelBase is one class, implements INotifyPropertyChanged interface, you replace ViewModelBase with BindableObject class in your model, every thing works. Because Bindableobject is abstract class, also implements INotifyPropertyChanged interface, so you can use BindableObject implement notification function.
https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.bindableobject?view=xamarin-forms
i want to declare bindableproperty inside viewmodelbase
I don't know why you want to declare bindableproperty in ViewModelBase, if you want to do this, you must inherit BindableObject class. GetValue(BindableProperty) and SetValue are used to access the values of properties that are implemented by a BindableProperty, these methods are adstract Bindableaobject method.
Because BindableObject class has implemented INotifyPropertyChanged, so you just make ViewModelBase inherit BindableObject.

Caliburn.Micro injecting a Collection with Xamarin.Forms Application

I am using Caliburn.Micro in combination with Xamarin.Forms. Within my App class, I register an interface ILicenseInfo with a class LicenseInfoImplementation via the SimpleContainer's PerRequest method.
CM then injects an object when my view model is created (see ViewModelOne) which is what I want. However, I don't see how I can extend this to a collection of objects. Lets say I would like CM to instantiate ViewModelTwo which expects a collection of object. How would I have to change App.cs and the XAML of ViewModelTwo to make that happen?
public partial class App : FormsApplication
{
private readonly SimpleContainer _container;
public App (SimpleContainer container)
{
InitializeComponent();
this._container = container;
// register interface and class
_container.PerRequest<ILicenseInfo, LicenseInfoImplementation>();
//....
}
}
public ViewModelOne(ILicenseInfo license)
{
// Great, Caliburn.Micro injects an LicenseInfoImplementation object
}
public ViewModelTwo(IEnumerable<ILicenseInfo> licenses)
{
// No idea
}
I finally used the following pattern. Not the most elegant way to do it but the best I found ...
public ViewModelTwo() : base (IoC.GetAll<ILicenseInfo>())
{
}
public ViewModelTwo(IEnumerable<ILicenseInfo> licenses)
{
// Do something with licenses
}

How to bind usercontrol to applications viewmodel

I am using the standard pivot template in my WP7 app.
I have the MainViewModel class defined with a few extra properties:
public class MainViewModel : INotifyPropertyChanged
{
...
private MyClass selectedKey_m;
public MyClass SelectedKey
{
get
{
...
}
set
{
if (value != this.selectedKey_m)
{
this.selectedKey_m = value;
NotifyPropertyChanged("SelectedKey");
}
}
}
}
The App class has a view model instance:
private static MainViewModel viewModel = null;
public static MainViewModel ViewModel
{
get
{
// Delay creation of the view model until necessary
if (viewModel == null)
viewModel = new MainViewModel();
return viewModel;
}
}
My MainPage.xaml.cs sets the DataContext:
DataContext = App.ViewModel;
From here, I can set up two way bindings on ListBoxes and I know it works because if I put a breakpoint on the SelecetdKey property in my viewmodel I can see the setter get called.
My problem is that I have my own user control, with a bindable property, bound to the SelectedKey property of the view model, but the property in my user control never gets set when the viewmodel gets updated and I can't figure out why.
Here is my user control:
public partial class MyUserControl : UserControl
{
public static readonly DependencyProperty SelectedKeyProperty = DependencyProperty.Register(
"SelectedKey", typeof(MyClass), typeof(MyUserControl), new PropertyMetadata(null));
public MyClass SelectedKey
{
get { return (MyClass)this.GetValue(SelectedKeyProperty); }
set { this.SetValue(SelectedKeyProperty, value); }
}
}
And here is the xaml in my main page:
<local:MyUserControl x:Name="myUC" SelectedKey="{Binding Path=SelectedKey}">
I would expect that the setter for the SelectedKey property of my user control to get called when the SelectedKey property of the view model gets changed, but it doesn't.
I've also tried setting the datacontext of my user control in the xaml:
DataContext="{Binding Path=App.ViewModel}"
The debugger does not step into the setter, don't know why.
Try adding a callback invoked on property value changes :
public static readonly DependencyProperty SelectedKeyProperty = DependencyProperty.Register(
"SelectedKey", typeof(MyClass), typeof(MyUserControl), new PropertyMetadata(MyPropertyChanged));
private static void MyPropertyChanged( object sender, DependencyPropertyChangedEventArgs args)
{
}
Solved. I had to add the static method as ptauzen suggested, but also remove the DataContext binding statement from my xaml :
DataContext="{Binding Path=App.ViewModel}"
Because the MainPage sets the datacontext in the constructor, so because my user control is a child of the main page, it inherits the data context. All I needed was to ensure the binding of my user controls properties were set up:
SelectedKey="{Binding SelectedKey}"

ASP.NET ActionFilters and inheritance

All my controllers inherit from a BaseController that has an ActionFilter attribute:
[AnalyticsData]
public class BaseController : Controller {}
public class AccountController : BaseController {}
Some of my Actions in my controllers reuse the AnalyticsData ActionFilter:
public class AccountController : BaseController
{
[AnalyticsData(Page="AccountProfile")]
public ActionResult Profile()
{
// return View
}
}
I notice that the AnalyticsData ActionFilter only runs once. This is a good thing and I only want it to run once, but I'm wondering how that happens. If I set my breakpoint inside the OnActionExecuting:
public class AnalyticsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// break point set here
}
}
...it only gets hit once when AccountController serves it Profile view.
How do ActionFilters and/or Attributes work that [AnalyticsData(Page="AccountProfile")] on the Action overrides/replaces [AnalyticsData] on BaseController?
The short answer is that the ASP.NET MVC framework code that retrievs the list of filters for each action removes duplicates (action filters of the same type) in such a way that it prefers actionfilters defined on the action method over ones defined on the controller (or its base class). In MVC 2 this logic is performed in a few internal methods in the ActionDescriptor class

ASP.NET MVC - Set Master View accordingly with Controller

By any chance, is there any easy way to set a default MasterView for all the actions inside a specific controller?
For example If I have the HomeController I want all the actions inside it to inherit the Site.Master as default, but If I am inside AccountsController I want all the action to inherit the Admin.Master and so on..
I managed to do it with:
return View("viewName", "masterName", objectModel);
But by doing this I have to apply it every time I call the View method.
I was looking for something simpler like on rails where we can declare:
class HomeController < ApplicationController
layout 'site'
def index
end
def create
...
end
class AccountsController < ApplicationController
layout 'admin'
def index
end
def create
...
end
Is that possible?
Thanks in advance
You could override OnActionExecuting in that Controller class.
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
ViewData["MasterfileToUser"] = "site";
}
Or if you like you can turn this into an ActionFilterAttribute you can apply on the controller or action level
using System;
using System.Web.Mvc;
public class MasterFileFilterAttribute : ActionFilterAttribute
{
public string Master { get; set; }
public override void OnActionExecuted( ActionExecutedContext filterContext)
{
if (filterContext.Result is ViewResult)
((ViewResult)filterContext.Result).MasterName = Master;
}
}
which you then in turn use like so:
[MasterFileFilterAttribute(Master = "site")]
public class HomeController : Controller
{
// Action methods
}

Resources