how to bind events fluent API mvvmCross - mvvmcross

I am trying to bind to the "scrolled" event from the CollectionView control in a Xamarin forms API using the mvvmcross framework. I have found Documentation that MvxEventNameTargetBinding
should work but no example on how. So I am binding the event using the fluent api in the View
set.Bind(CardCollectionView).For(v => v.ItemsSource).To(vm => vm.Cards).OneWay();
set.Bind(CardCollectionView).For("Scrolled").To(vm => vm.CardDetailScrollPositionChanged);
and the model has the Following API:
public IMvxCommand<EventArgs> CardDetailScrollPositionChanged { get; private set; }
...
CardDetailScrollPositionChanged = new MvxAsyncCommand<EventArgs>(async (EventArgs arg) => CardScrolledFunction(arg));
...
private async Task CardScrolledFunction(EventArgs args)
{
...
}
The code above can works in the way that the collection view is getting data from the model. Can any one please point out to me how to access the EventArgs following the mvvmCross framework using the fluent API so that my model knows what is the current visible item?
Thanks HP

I don't know how to do this with the fluent API and I'm not sure what CardCollectionView is. I guess it's your custom CollectionView class? What you could try is adding a method to the Scrolled EventHandler.
So in your view:
var viewModel = ViewModel as YourViewModelHere;
CardCollectionView.Scrolled += viewModel.CardDetailScrollPositionChanged;
and in your view model:
public void CardDetailScrollPositionChanged(object sender, EventArgs e)
{
...
}

Related

Windows Phone navigation to other page

I'm trying to navigate to another page. I'm using the MVVM pattern. So my button is binded to a command:
private ICommand inscriptionPage;
public ICommand InscriptionPage
{
get
{
if (this.inscriptionPage == null)
this.inscriptionPage = new MyCommand(() => callInscriptionFunction());
return this.inscriptionPage;
}
}
public void callInscriptionFunction()
{
PhoneApplicationPage nav = new PhoneApplicationPage();
nav.NavigationService.Navigate(new Uri("Views/Registration/Registration.xaml", UriKind.Relative));
}
I have this Exception at the last line:
object reference not set to an instance of an object
I check on the web, tried different option, but this error is still there.
Edit: I tried to change the command to put it directly in the code behind. But I have a Debugger.break error.
private void Button_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("Views/Registration/Registration.xaml", UriKind.Relative));
}
Thanks.
First, your Uri should begin with a slash, so change new Uri("Views/Registration/Registration.xaml", UriKind.Relative) to new Uri("/Views/Registration/Registration.xaml", UriKind.Relative). This should make your code behind work.
Second, creating a PhoneApplicationPage is a really strange and wrong idea. If you are not using a MVVM framework that provides navigation service, usu this
App.RootFrame.Navigate(new Uri("/Views/Registration/Registration.xaml", UriKind.Relative))

Castle Windsor: A better way to implement 2 levels of (nested) factories?

We have a pattern we've used several times, whereby we implement handlers and factories in separate Dlls. We configure exe's at runtime saying what dlls are loaded, and therefore what handlers are available to the app.
We do this because we have custom handling for some customers, also it allows great flexibility because we can quickly develop new handlers in isolation, and test and deploy them with confidence that we haven't even touched any other parts of a running application. We can also patch handlers by simply dropping in a single replacement dll, we have customers with strict change management procedures and they adore this.
To do this the pattern relies on two levels of factories, specific factories that implement specific handlers, and an overarching factory (which we call a Provider). The Provider chooses which handler factory to use to create a handler.
The question: Does Windsor contain something that would simplify this process for us?
Specifically I'm looking for something that could omit the Handler factory objects, it feels like something it should be able to do.
I've read up on the Typed Factory Facility and the UsingFactory & UsingFactoryMethod methods, but I can't see how they'd be any help here.
That said I often find the Castle Windsor documentation obtuse so I could be missing something obvious
Or is there just a better way of getting the same end goal that I haven't considered.
Here's some code to illustrate, first message, handler and factory interfaces
public interface IMessage
{
string MessageType { get; }
}
public interface IMessageHandler
{
void Process(IMessage message);
}
public interface IMessageHandlerFactory
{
bool CanProcessType(string type);
IMessageHandler Create();
}
In a second DLL we implement a handler and factory for Type1
public class Type1MessageHandler
: IMessageHandler
{
public void Process(IMessage message) { }
}
public class Type1MessageHandlerFactory
: IMessageHandlerFactory
{
public bool CanProcessType(string type)
{
return type == "Type1";
}
public IMessageHandler Create()
{
return new Type1MessageHandler();
}
}
In a third Dll we implement a handler and factory for Type2
public class Type2MessageHandler
: IMessageHandler
{
public void Process(IMessage message) { }
}
public class Type2MessageHandlerFactory
: IMessageHandlerFactory
{
public bool CanProcessType(string type)
{
return type == "Type2";
}
public IMessageHandler Create()
{
return new Type2MessageHandler();
}
}
In a windows service we implement the provider
public interface IMessageHandlerProvider
{
IMessageHandler Create(string messageType);
}
public class MessageHandlerProvider
: IMessageHandlerProvider
{
IEnumerable<IMessageHandlerFactory> factories;
public MessageHandlerProvider(IWindsorContainer wc)
{
factories = wc.ResolveAll<IMessageHandlerFactory>();
}
public IMessageHandler Create(string messageType)
{
foreach (var factory in factories)
if (factory.CanProcessType(messageType))
return factory.Create();
throw new UnableToFindMessageHandlerFactoryForType(messageType);
}
}
The service that actually needs the handlers only uses the Provider
public class MessageService
{
public MessageService(IMessageHandlerProvider handlerProvider) {}
}
What you are asking is indeed possible in Windsor with typed factories; instead of resolving all the factories in your provider and then looking for the ones that can process the message, you could ask Windsor for the handler that is linked to the message type and just use it. You don't really need the second level factory (IMessageHandlerFactory), because the handler can tell what message it will link to.
Here is a nice resource for this architecture (you've probably read this one already) which I'll summarize very quickly.
Given your interfaces, you start by registering all your handlers
container.Register(Classes.FromAssemblyInThisApplication()
.BasedOn<IMessageHandler>()
.WithServiceAllInterfaces());
Ok, now let's tell Windsor we want a factory that will return a IMessageHandler. What is nice is that we don't actually have to code anything for the factory.
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMessageHandlerProvider>().AsFactory());
Now we can start using the factory
var provider = container.Resolve<IMessageHandlerProvider>();
var msg = new Type2Message();
var msgHandler = provider.Create(msg.MessageType);
The problem is that since there is no link between our message handlers and the string we pass to the factory, Windsor returns the first registered instance of a IMessageHandler it finds. In order to create this link we can name each message handler after the message type it is supposed to handle.
You can do it in a variety of ways, but I like to create a convention where a message handler type tells what messages it can handle:
container.Register(Classes.FromAssemblyInThisApplication()
.BasedOn<IMessageHandler>()
.WithServiceAllInterfaces().Configure(c => {
c.Named(c.Implementation.Name.Replace("MessageHandler", string.Empty));
}));
Now you need to tell your factory that the message type must be used as the name of the handler you want to resolve. To do that, it is possible to use a class inheriting the DefaulTypedFactoryComponentSelector. We just override the way component names are determined and return the message type we are receiving:
public class MessageHandlerSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return arguments[0].ToString();
}
}
Now we can plug this selector in the factory
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMessageHandlerProvider>()
.AsFactory(c =>c.SelectedWith(new MessageHandlerSelector())));
Here is the full code to handle any messages:
var container = new WindsorContainer();
container.Register(Classes.FromAssemblyInThisApplication()
.BasedOn<IMessageHandler>()
.WithServiceAllInterfaces().Configure(c => {
c.Named(c.Implementation.Name.Replace("MessageHandler", string.Empty));
}));
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMessageHandlerProvider>().AsFactory(c =>c.SelectedWith(new MessageHandlerSelector())));
var provider = container.Resolve<IMessageHandlerProvider>();
var msg = new Type2Message();
var msgHandler = provider.Create(msg.MessageType);
msgHandler.Process(msg);
Here are some points I would like to underline:
as you guessed, you don't need the two factories: one is enough
the naming convention for the message handlers is not set in stone, and you could decide to have another mechanism in place to override the convention
I am not talking about releasing the components, but the links contain some info about it which you should look into
I didn't handle the case where no handler can be found, but Castle will throw by itself when it cannot resolve the handler with a ComponentNotFoundException
The system could perhaps be more robust if the handlers were explicit about the message types they handle. For example changing the interface to IHandlerOf<T> with T being a message type implementation.

mvvmcross and authentication

Is there a way to authenticate a user through Facebook in mvvmcross framework? I'm currently attempting use Mobile Azure Service to authenticate to Facebook, but I don't have any success. Without using mvvmcross, I can authenticate just fine.
Thank You!
Mark
In the MVVM sense what I've found is that no, you can not. Properties on the facebook login page are not bindable, nor should they be and is best treated as a modal view out of your control
What I would do is make it a view concern and use Xamarin.Auth to authenticate.
As an example let's say that you had a LoginView and LoginViewModel.
The LoginView provides your standard login Email/Password but with an option (button) to authenticate via facebook
From that view hook up to the touchupinside event of the facebooklogin button
this.btnFacebookLogin.TouchUpInside += (object sender, EventArgs e) =>
{
DoFacebookLogin ();
}
Then in your DoFacebookLogin method 'present' the viewcontroller for facebook as described here https://github.com/xamarin/Xamarin.Auth/blob/master/GettingStarted.md
For example :
private void DoFacebookLogin ()
{
var auth = new OAuth2Authenticator (
clientId: "yournumericclientidhere",
scope: "",
authorizeUrl: new Uri ("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new Uri ("http://www.facebook.com/connect/login_success.html"));
auth.AllowCancel = true;
auth.Completed += (sender, eventArgs) => {
DismissViewController (false, null);
if (eventArgs.IsAuthenticated) {
string user = eventArgs.Account.Serialize ();
var messenger = Mvx.Resolve<IMvxMessenger> ();
messenger.Publish (new FacebookLoggedIn (user));
} else {
// Cancelled here
}
};
var vc = auth.GetUI ();
this.PresentViewController (vc, true, null);
}
Cancelled does not need to be handled since the modal viewcontroller will take you back to your LoginView
On success that viewcontroller is dismissed then I would use mvx's interpretation of an eventaggregator (plugins.messenger) to send a message to the viewmodel that the facebook modal view is closed, with that message you can pass the account details - accesstoken etc back to the viewmodel to do as you wish.
View (as above) :
string user = eventArgs.Account.Serialize();
var messenger = Mvx.Resolve<IMvxMessenger> ();
messenger.Publish (new FacebookLoggedIn (user));
Message Class in your PCL :
public class FacebookLoggedIn : MvxMessage
{
public FacebookLoggedIn(object sender) : base(sender) {}
}
ViewModel also in your PCL :
public LoginViewModel()
{
var messenger = Mvx.Resolve<IMvxMessenger> ();
user = messenger.SubscribeOnMainThread<FacebookLoggedIn> (OnFacebookLoggedIn);
}
private void OnFacebookLoggedIn (FacebookLoggedIn MvxMessage)
{
... do something with the accesstoken? call your IUserService etc
ShowViewModel<MainViewModel> ();
}
Since you're dismissing the facebook viewcontroller you'll find yourself back on the loginview momentarily before automatically navigating to the MainView
In your view project you need to ensure the plugin is loaded otherwise you'll receive an error during construction of the viewmodel, so in setup.cs
protected override void InitializeLastChance ()
{
Cirrious.MvvmCross.Plugins.Messenger.PluginLoader.Instance.EnsureLoaded();
base.InitializeLastChance ();
}
Additionally you can also store the account credentials locally, this is described on the Xamarin.Auth link under AccountStore.Create().Save. Note that if you receive a platform not supported exception then add PLATFORM_IOS as a preprocessor directive to your project.
I realise the question is a couple of months old but since it rates high on google thought I'd provide an answer since there isn't any

Linq's DataContexts and "Unit of Work" pattern. Is my approach ok?

Following the directions from many articles, I've decided to implement the Unit of work pattern to my Linq2SQL DataContexts in my ASP.Net WebForms Application, but I'm not sure if I'm on the right way.
Here's what I'm accomplishing so far:
1 - On every Request, I catch the Application_AcquireRequestState event (which has access to Session data) in Global.asax and instantiate a new DataContext to bind it to the user's Session:
void Application_AcquireRequestState(object sender, EventArgs e)
{
// Check if the request is for a Page, Page Method or Handler
if (new Regex(#"\.(aspx|ashx)(/.*)?$").IsMatch(HttpContext.Current.Request.Url.AbsolutePath))
{
MyCompany.MyDatabaseDataContext myDatabaseDataContext = new MyCompany.MyDatabaseDataContext();
HttpContext.Current.Session["myDatabaseDataContext"] = myDatabaseDataContext;
}
}
2 - Every Data Access Layer Object (DAO) inherits from a base DAO: GenericDAO:
public class GenericDAO
{
private MyDatabaseDataContext _dbMyDatabase;
protected MyDatabaseDataContext dbMyDatabase
{
get
{
if (_dbMyDatabase == null)
_dbMyDatabase = HttpContext.Current.Session["myDatabaseDataContext"] as MyDatabaseDataContext;
return _dbMyDatabase;
}
}
}
3 - So, in every operation, the DAO use the DataContext Property from its parent class:
public class MyTableDAO : GenericDAO
{
public List<MyTable> getAll()
{
return dbMyDatabase.GetTable<MyTable>().ToList();
}
}
Here's my concerns...
First of all, is it ok to store the DataContext in the user's Session? What would be another option? My app has a lot of PageMethods calls, so I'm worried the DTX would be invalidated between their async requests if it is stored in the session.
Do I need to capture the Application_ReleaseRequestState event to Dispose() of the DataContext and remove it from the session?
If I don't need to Dispose of it, in every Application_AcquireRequestState, would it be better to Remove DTX from Session - Create DTX - Store it or just Refresh it?
Also, if I don't need to Dispose of it, what about Connections? Would it handle them automatically or I would need to control them too?
I appreciate your time and help :)
-- EDIT
Here's the code I've reached, following #ivowiblo's suggestion:
Global.asax
void Application_BeginRequest(object sender, EventArgs e)
{
if (new Regex(#"\.(aspx|ashx)(/.*)?$").IsMatch(HttpContext.Current.Request.Url.AbsolutePath))
{
MyCompany.MyDatabaseDataContext myDatabaseDataContext = new MyCompany.MyDatabaseDataContext();
HttpContext.Current.Items["myDatabaseDataContext"] = ceabsDataContext;
}
}
void Application_EndRequest(object sender, EventArgs e)
{
if (new Regex(#"\.(aspx|ashx)(/.*)?$").IsMatch(HttpContext.Current.Request.Url.AbsolutePath))
{
if (HttpContext.Current.Items["myDatabaseDataContext"] != null)
{
System.Data.Linq.DataContext myDbDtx = HttpContext.Current.Items["myDatabaseDataContext"] as System.Data.Linq.DataContext;
if (myDbDtx != null)
myDbDtx.Dispose();
}
}
}
GenericDAO
public class GenericDAO
{
protected MyDatabaseDataContext dbMyDatabase
{
get
{
return HttpContext.Current.Items["myDatabaseDataContext"] as MyDatabaseDataContext;
}
}
}
Simple as that!
The best approach is to put it on HttpContext.Current.Items, creating the DataContext on RequestBegin and dispose it in RequestEnd. In msdn there's an interesting article about the better management of the DataContext, where it's suggested to have short-time DataContext instances.
This pattern is called Open session in view and was created for using NHibernate in web environments.
You say you are implementing unit-of-work, but by storing it in the cache you do not really stick to that unit-of-work.
My advice is to create a new DataContext for every request and not to cache it anyware.

How to add a type forward to an existing Castle Windsor registration

I'm currently registering a bunch of stuff at one point in my initialisation sequence
Container.Register(AllTypes.FromAssemblyContaining<MyAssembly>()
.BasedOn(typeof(IRepository<>))
.WithService.Self().Configure(c => c.LifeStyle.Transient));
I'm using WithService.Self so that it doesn't automatically pick up AllInterfaces, so that the interface that I will want to add later on as a type forward has not already been added.
I'd like then (later on) to be able to add a type forward to one of the already registered components, and Intellisense on the ForwardedTypes property suggested using .Forward(typof()) e.g.
Container.Register(Component.For<IOtherInterface>()
.Forward(typeof(IOtherInterface))
.ImplementedBy<AlreadyRegisteredType>().LifeStyle.Transient);
Is this possible?
EDIT:
I've been trying to get the stuff that Krzysztof has suggested working so I've generated a test project (below). I've tried various combinations to get the ConfigureFor to forward IMyInterface to MySecondType, but just can't get it to work, when done as a second step after initial registration of my component types. I'm probably being dim, but I'm just not getting how the ConfigureFor command works, and the documentation is a little sketchy (non-existant) on the subject.
namespace TestProject1
{
public class MyType : IMyInterface
{
public virtual string MyProperty { get; set; }
}
public class MySecondType : IMyInterface
{
public virtual string MySecondProperty { get; set; }
}
public interface IMyInterface
{
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
//New Container
var container = new WindsorContainer();
//Register Types
container.Register(
AllTypes.FromAssemblyContaining<MyType>().BasedOn<IMyInterface>().WithService.Self().Configure(
c => c.LifeStyle.Transient));
//Other stuff happens here...
//Now Register our interface as a forward
container.Register(AllTypes.FromAssemblyContaining<IMyInterface>()
.BasedOn<IMyInterface>()
.WithService.Base()
.ConfigureFor<IMyInterface>(r => r.Forward<MySecondType>()).Configure(c => c.LifeStyle.Transient));
var typeA = new MySecondType();
var typeB = container.Resolve<IMyInterface>();
Assert.IsInstanceOfType(typeB.GetType(), typeA.GetType());
}
}
}
What you described in the comment is registering another component for the AlreadyRegisteredType.
If you want to add a forward to the same component use
ConfigureFor<AlreadyRegisteredType>(c => c.Forward<IOtherInterface>())
full example:
Container.Register(AllTypes.FromThisAssembly()
.BasedOn<IEmptyService>()
.WithService.Base()
.ConfigureFor<EmptyServiceComposite>(r => r.Forward<EmptyServiceComposite>()));
Once you registered some type
Container.Register(Component.For<SomeType>());
you can forward some interface to it in this way:
Container.Register(Component.For<ISomeInterface>()
.UsingFactoryMethod<ISomeInterface>(kernel => kernel.Resolve<SomeType>()));