When attempting to change a ViewModel from an ObservableObject to ObservableValidator the compiler throws
Error CS0653 Cannot apply attribute class 'ObservableValidator' because it is abstract
Simplified original working class definition that inherits from ViewModelBase so that navigation works.
[ObservableObject]
internal sealed partial class AddSimCardViewModel : ViewModelBase
{
private readonly NavigationService _addSimCardViewNavigationService;
[ObservableProperty]
private string? _phoneNumber;
public AddSimCardViewModel(NavigationService addSimCardViewNavigationService)
{
_addSimCardViewNavigationService = addSimCardViewNavigationService;
}
}
Simplified replacement class definition that throws error
[ObservableValidator]
internal sealed partial class AddSimCardViewModel : ViewModelBase
{
private readonly NavigationService _addSimCardViewNavigationService;
[ObservableProperty]
private string? _phoneNumber;
public AddSimCardViewModel(NavigationService addSimCardViewNavigationService)
{
_addSimCardViewNavigationService = addSimCardViewNavigationService;
}
}
internal sealed partial class AddSimCardViewModel : ViewModelBase, ObservableObject
and
internal sealed partial class AddSimCardViewModel : ViewModelBase, ObservableValidator
won't work as both Observable classes are base classes.
If ObservableValidator won't work as an attribute how could I change my NavigationService to work with differnet ViewModels?
internal class ViewModelBase
{
public virtual void Dispose() { }
}
internal sealed class NavigationService
{
private readonly NavigationStore _navigationStore;
private readonly Func<ViewModelBase> _createViewModel;
public NavigationService(NavigationStore navigationStore,
Func<ViewModelBase> createViewModel)
{
_navigationStore = navigationStore;
_createViewModel = createViewModel;
}
internal void Navigate()
{
_navigationStore.CurrentViewModel = _createViewModel();
}
}
Edited to add NavigationStore that calls Dispose on ViewModel
I have been using https://github.com/SingletonSean/reservoom as the basis for this project.
internal sealed class NavigationStore
{
private ViewModelBase _currentViewModel;
internal ViewModelBase CurrentViewModel
{
get => _currentViewModel;
set
{
_currentViewModel?.Dispose();
_currentViewModel = value;
OnCurrentViewModelChanged();
}
}
public event Action CurrentViewModelChanged;
private void OnCurrentViewModelChanged()
{
CurrentViewModelChanged?.Invoke();
}
}
The only thing you have in viewmodelbase is dispose and it has no implementation.
That should be an interface ( but do you really need it at all ?).
You can implement as many interfaces as you like in a class, but inherit from only one class.
Then your viewmodels can inherit observableobject or observablevalidator and implement whatever interfaces you like.
In order to avoid any confusion, I prefer not to use attributes for the classes and instead use regular c#:
public partial class NewTransactionViewModel : ObservableValidator, IInitiatedViewModel
My thinking:
One should avoid having any need to explicitly dispose anything out a viewmodel. Only reference private members with any event handling. Use weak events or weak event event messenger across objects. Have small methods with use to instantiate anything where disposing is critical. There are very few things I find I need to explicitly dispose.
Use an interface for anything you want all viewmodels to do.
I have
interface IInitiatedViewModel
{
Task Initiate();
}
Any viewmodel set up is then done in the initiate task.
I can then do something like:
await Task.Run(() =>((IInitiatedViewModel)CurrentViewModel).Initiate());
On any viewmodel I just instantiated and it gets it's data etc.
If there's no setup then don't apply that interface.
Related
I have a WPF application where I have a dedicated presenter for each view and some parts of the application are tasks that uses AbstractTaskPresenter like below.
TaskPresenter
public sealed class AbcTaskPresenter : AbstractTaskPresenter<AbcTaskViewModel>
{
private AbcTaskPresenter() : base(new AbcTaskViewModel())
{
}
//ViewModel is used here
...
}
AbstractTaskPresenter
public abstract class AbstractTaskPresenter<TViewModel> : PresenterBase<TViewModel> where TViewModel : AbstractTaskViewModel
{
public event EventHandler SaveTaskRequested;
//ViewModel is also used here
...
}
PresenterBase
public abstract class PresenterBase<TViewModel> : IDisposable where TViewModel : ViewModelBase
{
protected TViewModel ViewModel { get; }
//ViewModel is also used here
...
}
And my problem is here...
In a main application presenter, I declare this global variable that says
protected AbstractTaskPresenter commonPresenter{ get; set; }
So in the Main application presenter, I can register for the AbstractTaskPersenter events.
But the problem is here. Now since I have the Generics in the abstract classes, the variable declaration always has this error. Not sure how to go about this.
Thanks in advance.
Currently I have a simple generic abstract class with one service parameter in constructor which is resolved by dependency injection.
public abstract class CosmosCommandHandler<T>
{
protected readonly ICosmosStore<T> _cosmosStore;
protected CosmosCommandHandler(ICosmosStore<T> cosmosStore)
{
_cosmosStore = cosmosStore;
}
}
and some concrete class inheriting from it
public class FooCommandHandler : CosmosCommandHandler<Foo>
{
private readonly IFooService _fooService;
public FooCommandHandler(ICosmosStore<Foo> cosmosStore, IFooService fooService)
: base(cosmosStore)
{
_fooService = fooService;
}
}
This is all fine, but I want to add a new service to abstract class and resolve it with DI as well. My idea is that I should use constructor chaining for this, but it's not working out.
Something like this.
public abstract class CosmosCommandHandler<T>
{
private readonly IAuditService _auditService;
protected readonly ICosmosStore<T> _cosmosStore;
private CosmosCommandHandler(ICosmosStore<T> cosmosStore, IAuditService auditService)
{
_cosmosStore = cosmosStore;
_auditService = auditService;
}
protected CosmosCommandHandler(ICosmosStore<T> cosmosStore)
: this(cosmosStore, IAuditService auditService)
{
}
}
Obviously I could just pass the IAuditService from FooCommandHandler just like ICosmosStore, but that doesn't seem right as FooCommandHandler has nothing to do with IAuditService. It is out of its scope.
Is this possible to achieve?
If IAuditService is out of the FooCommandHandler scope, then create child of your CosmosCommandHandler class which will have that IAuditService. And that child also could be abstract class.
Also, you could create additional overloaded constructor for your CosmosCommandHandler class - and that FooCommandHandler class does not need to use it. But that also breaks the concept of inheritance because FooCommandHandler class has nothing to do with IAuditService.
public sealed class HomePage : Page
{
public override void GoTo()
{
throw new System.NotImplementedException();
}
public override void IsAt() => Assert.IsTrue(Browsers.Title.Equals("home"));
}
I have bunch of page object classes like HomePage which I want to turn into a singleton.
I was looking at Jon Skeet's site on implementing the Singleton pattern.
An example of how to implement the Singleton pattern as per the site mentioned above:
public sealed class Singleton {
private static readonly Singleton instance = new Singleton();
static Singleton() {}
private Singleton() {}
public static Singleton Instance {
get {
return instance;
}
}
}
I want to implement this for all my page objects. All my page objects inherit from an abstract base class Page.
public abstract class Page
{
private static readonly Page instance = new Page();
public abstract void IsAt();
public abstract void GoTo();
}
I'm trying to implement the Singleton pattern I mentioned earlier on my Page base class. But the problem is my Page class is abstract and I can't do the following:
private static readonly Page instance = new Page(); // Since Page is abstract I can't do this.
How can I implement the singleton pattern without having to implement it for each child class individualy?
Your question is specifically about being able to implement the singleton pattern solely using the base class, without making any code changes to the derived classes.
It's possible to do something like this:
public abstract class Page
{
// Your normal Page base class things
}
public abstract class Page<T> : Page where T : Page<T>, new()
{
// Or whatever singleton pattern you want to implement
public static readonly T Instance = new T();
}
public class HomePage : Page<HomePage>
{
}
This lets you write:
var homePage = HomePage.Instance;
This works because Page<T> has its own set of static data which is separate for each T - so Page<HomePage> has separate static data to Page<LogInPage>.
You will however need to modify each of your pages to derive from Page<PageSubclass>, rather than from Page.
That said, I would take the simpler route of adding code like:
public static readonly HomePage Instance = new HomePage();
to each of your Page subclasses. This is significantly less "magic", doesn't rely on reflection to instantiate the pages, and will only take you a few minutes to add to even 70 page objects. After all, you'll have to modify them all to derive from Page<T> to use this pattern anyway.
You can kind of do this, but just because you can do something, it does not mean it is a good idea. Think if it really makes the code easier to understand or not. Sometimes the amount of abstraction makes it just not worth it
public abstract class Page<T> where T: new()
{
public static readonly T instance = new T();
public abstract void GoTo();
}
public class Home : Page<Home>
{
public override void GoTo()
{
Console.WriteLine("goto home");
}
}
public class Login : Page<Login>
{
public override void GoTo()
{
Console.WriteLine("goto Login");
}
}
Then:
Home.instance.GoTo();
Login.instance.GoTo();
The thing is it is not a nice pattern. You might be better doing something like this so you avoid singletons:
pages["Home"].Goto();
I have multiple ViewModels and use ViewModelBase as an abstract class in all of them. I want to grab the current property values from one class in another. Creating an instance is not desirable, making the property static gets me what I want. However by doing this I lose out on the INotifyPropertyChange Im using with ViewModelBase.Set() since Set() is a non-static method.
Whats the alternative where I can get the property value, yet still keep the benefits of ViewModelBase in MVVM?
public class SampleViewModel : ViewModelBase
{
private static bool _sample;
public SampleViewModel()
{
}
public static bool GetValue
{
get { return _sample; }
set { Set(ref _sample, value); }
}
}
public class MyClassViewModel : ViewModelBase
{
public MyClassViewModel()
{
bool myValue = SampleViewModel.GetValue;
}
}
ParentVM creates a ChildVM, exposing it via a ChildVM property
ParentView handles the resultant PropertyChanged event, creating a ChildView, setting its DataContext to ChildVM.
See here for details.
Or use MVVM Light Toolkit's Messaging Services to pass values to view Models.. But I don't like it.
I'm trying to create a class hierarchy such that I can have:
SpecificScreenController < ScreenController < Singleton
So far I have these set up as:
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance{ get{... return _instance;} }
}
public abstract class ScreenController<T> : Singleton<T> where T : MonoBehaviour
{
public GAME_SCREEN GameScreen;
//many more ScreenController common properties/fields/methods
}
public class SpecificScreenController : ScreenController<SpecificScreenController>
{
//subclass specific properties, overriden ScreenController methods etc.
}
This way I can use SpecificScreenController.Instance.GameScreen; This works, so far, so good.
What I want to now do with this is, for instance:
List<ScreenController> screenControllers = new List<ScreenController>();
screenControllers.Add(SpecificScreenController.Instance);
ScreenController s = screenControllers.Find(i => i.GameScreen == GAME_SCREEN.THING);
But, of course ... this won't compile because ScreenController now requires a Generic Type etc. What idiom can/should I use to preserve the Singleton behavior and ScreenController sub/superclasses ?
The problem here is one of covariance. You're assuming that if SpecificScreenController inherits from MonoBehaviour then ScreenController<SpecificScreenController> also inherits from ScreenController<MonoBehaviour>. It doesn't. You can't do this cast.
As there seem to be no really clean solutions to this issue I ended up removing Singleton from my class hierarchy and copy-pasted non-generic versions of the singleton property get/instantiate code into each of the classes that I wanted to be singletons.
public abstract class ScreenController : MonoBehaviour
{
}
public class SpecificScreenController : ScreenController
{
private static SpecificScreenController _instance;
public static SpecificScreenController Instance{ get{... return _instance;}
}