I'm currently diving into the world of Xamarain with the MvvmCross framework. In my current project I want to make use of a MVVM base ViewModel to be able to reuse some of my code in other ViewModels.
When trying to implement this I've ran into a problem when using the MvxViewModel which supports passing parameters between navigation.
public abstract class BaseViewModel<TParameter> : MvxViewModel, IMvxViewModel<TParameter> where TParameter : class
{
protected readonly IMvxNavigationService _navigationService;
public BaseViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public new abstract Task Initialize(TParameter parameter);
}
This way I'm able to use the BaseViewModel as following.
public class ExampleViewModel : BaseViewModel<ExampleParameters>
{
private ExampleParameters _parameter;
public ExampleViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
}
public override Task Initialize(ExampleParameters parameter)
{
return Task.Run(() => { _parameter = parameter; });
}
}
In this situation I think this is a pretty good solution. The ExampleViewModel even tells me I need to implement the Initialize Task when I've forgotten.
Still this solution is not great in every situation. When I have ViewModel that doesn't require the passing of parameters I still need to specify a parameters object and implement the Initialize method.
public class ParameterlessViewModel : BaseViewModel<object>
{
public ParameterlessViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
}
public override Task Initialize(object parameter)
{
return Task.Run(() => { });
}
}
When removing the abstract method from the BaseViewModel I wont need to implement the Initialize method but then I won't be forced to implement it when I'm creating a ViewModel that requires the passing of parameters.
The above solution is workable but I'm curious if anyone ran into this same problem and maybe has a better solution? One which is good in both situations without having to setup two BaseViewModel classes.
Kind regards,
Jop Middelkamp
The documentation for this states: https://www.mvvmcross.com/documentation/fundamentals/navigation
If you have a BaseViewModel you might not be able to inherit MvxViewModel<TParameter> or MvxViewModel<TParameter, TResult> because you already have the BaseViewModel as base class. In this case you can implement the following interface:
IMvxViewModel<TParameter>, IMvxViewModelResult<TResult> or IMvxViewModel<TParameter, TResult>
In case you use TResult you can just copy the source code into your viewmodel:
public override TaskCompletionSource<object> CloseCompletionSource { get; set; }
public override void ViewDestroy()
{
if (CloseCompletionSource != null && !CloseCompletionSource.Task.IsCompleted && !CloseCompletionSource.Task.IsFaulted)
CloseCompletionSource?.TrySetCanceled();
base.ViewDestroy();
}
Do we do the add the Interface IMvxViewModel in the base class or the device class, can you give a simple example
In this case you can implement the following interface:
IMvxViewModel<TParameter>, IMvxViewModelResult<TResult> or IMvxViewModel<TParameter, TResult>
Related
I'm working on an ASP.NET MVC 5, I want to log all exceptions that occurs in the controller's actions.
To accomplish this I'm creating a custom aspect using PostSharp (in a dll), there I've already created the code to write the log files, now I want that the aspect can be controller-wide (do not want to apply it by hand to all methods).
The aspect's code looks like this:
using System;
using PostSharp.Aspects;
namespace Banlinea.Ceb.Domain.Aspects
{
public class LogException : OnExceptionAspect
{
public LogException()
{
ApplyToStateMachine = true;
}
public override void OnException(MethodExecutionArgs args)
{
//Code for logging the exception
args.FlowBehavior = FlowBehavior.ThrowException;
}
}
}
Now, what I want in my controller is to do something like this:
[LogException]
public class MyController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Other()
{
return View();
}
public ActionResult Another()
{
return View();
}
}
Just decorate the class, How can I do that?
you can do this byimplementing IAspectProvider
http://doc.postsharp.net/iaspectprovider
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type type = (Type)targetElement;
return type.GetMethods().Select(
m => return new AspectInstance(targetElement, new LogException()) );
}
You can apply PostSharp aspects across your codebase by using a feature called attribute multicasting.
For example, when you apply a method-level aspect on a class level or assembly level, then it is automatically copied to all the methods in the corresponding class or assembly. You can additionally filter the target elements by setting the attribute properties, such as AttributeTargetTypes, AttributeTargetMemberAttributes etc.
The sample code from your question should actually work as you expect.
I have a rather simple theoretical question regarding OOP (in AS3) that I don't know how to google:
I need something like an abstract class, which would require that dependant class implements some interface, like this:
Interface ISomething
{
public function somethingize(otherThing:type):void;
}
abstract public class AbstractSomething implements ISomething
{
public function AbstractSomething()
{
// ...
}
public function doSomething():void
{
//code here
// ...
this.somethingize();
// ...
}
}
Is the only way to achieve such a thing is to drop an "abstract" keyword, and move somethingize to SomethingWrapper (with an implementation of throwing an "unimplemented exception"), or is there some better way to model it?
ActionScript doesnt support Abstract classes (unfortunately).
I think there are a few techniques out there to try and mimic abstracts, but my way is too just throw errors in my abstract classes to stop them being used directly, eg:
public class AbstractSomething implements ISomething
{
public function AbstractSomething()
{
throw new Error("this is an abstract class. override constructor in subclass");
}
public function doSomething():void
{
throw new Error("this is an abstract class. override doSomething in subclass");
}
}
Without more information about the specific implementation, I would prefer composition over inheritance in this case, specifically dependency injection.
public interface ISomething {
function somethingize(thing:*):void;
}
public class SomeWorker {
private var _something:ISomething;
public function SomeWorker(something:ISomething) {
this._something = something;
}
public function doSomething():void {
// work
this._something.somethingize(obj);
// more work
}
}
Inherrited classes of SomeWorker could inject the correct implementation of ISomething for the work they need to do, or that dependency could be resolved somewhere else.
I have an MVVM Cross application running on Windows Phone 8 which I recently ported across to using Portable Class Libraries.
The view models are within the portable class library and one of them exposes a property which enables and disables a PerformanceProgressBar from the Silverlight for WP toolkit through data binding.
When the user presses a button a RelayCommand kicks off a background process which sets the property to true which should enable the progress bar and does the background processing.
Before I ported it to a PCL I was able to invoke the change from the UI thread to ensure the progress bar got enabled, but the Dispatcher object isn't available in a PCL. How can I work around this?
Thanks
Dan
All the MvvmCross platforms require that UI-actions get marshalled back on to the UI Thread/Apartment - but each platform does this differently....
To work around this, MvvmCross provides a cross-platform way to do this - using an IMvxViewDispatcherProvider injected object.
For example, on WindowsPhone IMvxViewDispatcherProvider is provided ultimately by MvxMainThreadDispatcher in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxMainThreadDispatcher.cs
This implements the InvokeOnMainThread using:
private bool InvokeOrBeginInvoke(Action action)
{
if (_uiDispatcher.CheckAccess())
action();
else
_uiDispatcher.BeginInvoke(action);
return true;
}
For code in ViewModels:
your ViewModel inherits from MvxViewModel
the MvxViewModel inherits from an MvxApplicationObject
the MvxApplicationObject inherits from an MvxNotifyPropertyChanged
the MvxNotifyPropertyChanged object inherits from an MvxMainThreadDispatchingObject
MvxMainThreadDispatchingObject is https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxMainThreadDispatchingObject.cs
public abstract class MvxMainThreadDispatchingObject
: IMvxServiceConsumer<IMvxViewDispatcherProvider>
{
protected IMvxViewDispatcher ViewDispatcher
{
get { return this.GetService().Dispatcher; }
}
protected void InvokeOnMainThread(Action action)
{
if (ViewDispatcher != null)
ViewDispatcher.RequestMainThreadAction(action);
}
}
So... your ViewModel can just call InvokeOnMainThread(() => DoStuff());
One further point to note is that MvvmCross automatically does UI thread conversions for property updates which are signalled in a MvxViewModel (or indeed in any MvxNotifyPropertyChanged object) through the RaisePropertyChanged() methods - see:
protected void RaisePropertyChanged(string whichProperty)
{
// check for subscription before going multithreaded
if (PropertyChanged == null)
return;
InvokeOnMainThread(
() =>
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(whichProperty));
});
}
in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNotifyPropertyChanged.cs
This automatic marshalling of RaisePropertyChanged() calls works well for most situations, but can be a bit inefficient if you Raise a lot of changed properties from a background thread - it can lead to a lot of thread context switching. It's not something you need to be aware of in most of your code - but if you ever do find it is a problem, then it can help to change code like:
MyProperty1 = newValue1;
MyProperty2 = newValue2;
// ...
MyProperty10 = newValue10;
to:
InvokeOnMainThread(() => {
MyProperty1 = newValue1;
MyProperty2 = newValue2;
// ...
MyProperty10 = newValue10;
});
If you ever use ObservableCollection, then please note that MvvmCross does not do any thread marshalling for the INotifyPropertyChanged or INotifyCollectionChanged events fired by these classes - so it's up to you as a developer to marshall these changes.
The reason: ObservableCollection exists in the MS and Mono code bases - so there is no easy way that MvvmCross can change these existing implementations.
If you don't have access to the Dispatcher, you can just pass a delegate of the BeginInvoke method to your class:
public class YourViewModel
{
public YourViewModel(Action<Action> beginInvoke)
{
this.BeginInvoke = beginInvoke;
}
protected Action<Action> BeginInvoke { get; private set; }
private void SomeMethod()
{
this.BeginInvoke(() => DoSomething());
}
}
Then to instanciate it (from a class that has access to the dispatcher):
var dispatcherDelegate = action => Dispatcher.BeginInvoke(action);
var viewModel = new YourViewModel(dispatcherDelegate);
Or you can also create a wrapper around your dispatcher.
First, define a IDispatcher interface in your portable class library:
public interface IDispatcher
{
void BeginInvoke(Action action);
}
Then, in the project who has access to the dispatcher, implement the interface:
public class DispatcherWrapper : IDispatcher
{
public DispatcherWrapper(Dispatcher dispatcher)
{
this.Dispatcher = dispatcher;
}
protected Dispatcher Dispatcher { get; private set; }
public void BeginInvoke(Action action)
{
this.Dispatcher.BeginInvoke(action);
}
}
Then you can just pass this object as a IDispatcher instance to your portable class library.
Another option that could be easier is to store a reference to SynchronizationContext.Current in your class's constructor. Then, later on, you can use _context.Post(() => ...) to invoke on the context -- which is the UI thread in WPF/WinRT/SL.
class MyViewModel
{
private readonly SynchronizationContext _context;
public MyViewModel()
{
_context = SynchronizationContext.Current.
}
private void MyCallbackOnAnotherThread()
{
_context.Post(() => UpdateTheUi());
}
}
How can i produce the same output as specified below using the TypedFactoryFacility?
public class Something
{
public void Initialize(Whatever instance) {}
}
public interface ISomethingFactory
{
Something Create(Whatever instance);
}
internal class SomethingFactory : ISomethingFactory
{
private readonly IWindsorContainer _container;
public SomethingFactory(IWindsorContainer container)
{
_container = container;
}
public Something Create(Whatever instance)
{
Something item = _container.Resolve<Something>();
item.Initialize(instance);
return item;
}
}
So I want to replace the manual factory with a proxy-generated ITypedFactoryFacility, but I cant find a way to invoke something on the resolved component after creation. I looked at commission-concerns, but you don't have a reference to the CreationContext from a custom commision concern so that won't work. I could of course move the dependency to the ctor and provide an ctor override, but I think properties are good when you want to convey non-optional dependencies.
You don't need to invoke stuff on the instance upon creation - Windsor will automagically inject stuff when the name of the parameter in the factory method signature matches something that can be injected - be it constructor paramaters or public properties... short example (using a public property):
interface ISomeFactory
{
Something CreateSomething(object dataSource);
}
class Something
{
public object DataSource { get; set; }
}
Given that these are registered like this:
container.Register(Component.For<ISomeFactory>().AsFactory(),
Component.For<Something>().Lifestyle.Transient)
you can resolve instances of Something like this:
var aintThatSomething = someFactory.CreateSomething(new [] {"ZOMG!", "w00t!"});
Remember that if something inside the burden associated with the instance of Something requires decommissioning, you need to provide an appropriate Release method on the factory as well.
Consider the following example:
public interface ITask
{
void Execute();
}
public class LoggingTaskRunner : ITask
{
private readonly ITask _taskToDecorate;
private readonly MessageBuffer _messageBuffer;
public LoggingTaskRunner(ITask taskToDecorate, MessageBuffer messageBuffer)
{
_taskToDecorate = taskToDecorate;
_messageBuffer = messageBuffer;
}
public void Execute()
{
_taskToDecorate.Execute();
Log(_messageBuffer);
}
private void Log(MessageBuffer messageBuffer)
{}
}
public class TaskRunner : ITask
{
public TaskRunner(MessageBuffer messageBuffer)
{
}
public void Execute()
{
}
}
public class MessageBuffer
{
}
public class Configuration
{
public void Configure()
{
IWindsorContainer container = null;
container.Register(
Component.For<MessageBuffer>()
.LifeStyle.Transient);
container.Register(
Component.For<ITask>()
.ImplementedBy<LoggingTaskRunner>()
.ServiceOverrides(ServiceOverride.ForKey("taskToDecorate").Eq("task.to.decorate")));
container.Register(
Component.For<ITask>()
.ImplementedBy<TaskRunner>()
.Named("task.to.decorate"));
}
}
How can I make Windsor instantiate the "shared" transient component so that both "Decorator" and "Decorated" gets the same instance?
Edit: since the design is being critiqued I am posting something closer to what is being done in the app. Maybe someone can suggest a better solution (if sharing the transient resource between a logger and the true task is considered a bad design)
Edit2: Castle3 has added support for this (http://docs.castleproject.org/Windsor.Whats-New-In-Windsor-3.ashx) by introducing the "Bound" lifestyle
'Transient' explicitly means 'non-shared', so what you are asking is conceptually the wrong thing to do. The correct solution is to register Shared as a Singleton instead of Transient:
container.Register(Component.For<Shared>());
(Singleton is the default lifetime in Windsor.)
However, I suspect that behind the stated question lies a much more complex problem. I'm guessing that you need Shared to be Transient because you need it with this lifestyle for a lot of other cases, but exactly when it comes to the relationship between Decorator and Decorated you need to share them.
I still think this sounds like a Design Smell, but there are at least two ways you can achieve this result.
The first option involves prematurely resolving Shared and explicitly supply the resolved instance to the configuration of the two IFoo registrations:
container.Register(Component.For<Shared>().LifeStyle.Transient);
var r = container.Resolve<Shared>();
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorator>()
.DependsOn(new { resource = r }));
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorated>()
.DependsOn(new { resource = r }));
The second option is to make a specialized, named registration for Shared that is used only by the IFoo registrations:
container.Register(Component.For<Shared>().LifeStyle.Transient);
container.Register(Component.For<Shared>().Named("shared"));
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorator>()
.ServiceOverrides(new { resource = "shared" }));
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorated>()
.ServiceOverrides(new { resource = "shared" }));