What is the correct way to open a View in mvvmcross from a non-view? From within a viewmodel we would use ShowViewModel<>(..).
Specifically we are responding to a push notification opening the app (with a custom payload) which dictates a view that should be loaded.
We have a hackety workaround just for proof of concept, just wanted to get an idea of the correct MVX approach
I don't think there is a 'correct way' - I think it depends on your app and what you need it to do.
For some specific cases - e.g. ViewModel->ViewModel and AppStart - MvvmCross provides some convenient methods:
you can call ShowViewModel in MvxViewModel
the app start can be overridden to use a hint object - see https://speakerdeck.com/cirrious/appstart-in-mvvmcross
But overall, any class can request a ShowViewModel by calling:
var viewDispatcher = Mvx.Resolve<IMvxViewDispatcher>();
viewDispatcher.ShowViewModel(new MvxViewModelRequest(
viewModelType,
parameterBundle,
presentationBundle,
requestedBy));
Further, there is a base class - MvxNavigatingObject.cs - which can help with this (it's a base class of MvxViewModel and MvxAppStart) - so you can easily provide one or more services like INavigateMyselfService who's implementations inherit from MvxNavigatingObject.
public interface INavigateMyselfService
{
void GoWild(string side);
}
public class NavigateMyselfService
: MvxNavigatingObject
, INavigateMyselfService
{
public void GoWild(string side)
{
ShowViewModel<WildViewModel>(new { side = side });
}
}
http://forums.xamarin.com/discussion/4694/conditionally-call-registerappstart-with-mvvmcross
Check the above link and you will get idea
In my case,I want to launch the app from secondary tile.For this,I have to launch specific page for Secondary tile.
My Initial App Start view model is LoginViewModel and my custom app start view model is HomeViewModel.
I controlled this from App.cs (Core) to MyCustomAppStart class.
Refer the above link
Related
In my MAUI, I register custom auth handlers using the following code snippet.
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCompatibility()
.UseMauiCommunityToolkit()
.RegisterRefitClients()
return builder.Build();
}
}
And my RegisterRefitClients extension method looks like this.
public static MauiAppBuilder RegisterRefitClients(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddRefitClient<IMyApiService>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri(Configuration.BASE_URL))
.AddHttpMessageHandler<AuthHeaderHandler>();
return mauiAppBuilder;
}
Here, the thing is, Configuration.BASE_URL can change at run time. By default, it always points to our production server. But the testers can change it to staging/dev server at run time. I want to invoke this method at run time, in order to set custom auth handler for the newly changed staging server.
But I cannot get the MauiAppBuilder instance anywhere in the app once it is initiated.
How do I call the RegisterRefitClients at run time?
RegisterRefitClients can not be called when the program start running. .NET MAUI enables apps to be initialized from a single location. The MauiProgram class is the entry point to the application, setting up configuration and wiring up services the application will use. Once the program starts, you can not change the MauiProgram.
I know about those MVVM purists and PasswordBox binding problem but I'm handling my login via codebehind and it works but for the life of me I can't get over using the DataContext from codebehind.
This event is attached to the PasswordChanged event of my passwordbox. Can this be handled in another way?
private void CopyPassword(object sender, RoutedEventArgs e)
{
if(e.Source is PasswordBox)
{
var source = e.Source as PasswordBox;
if(source.DataContext is LoginViewModel)
{
var vm = source.DataContext as LoginViewModel;
vm.Password = source.Password;
}
}
}
Yes it can be handled in many ways. There is nothing wrong with code-behind. Your current solution has the problem that you're tying concrete viewmodel with PasswordBox which makes it NON reusable for other viewmodels.
Better way is to write attached property with event listeners.
There are many resources that can get you started, check the related links on right.
http://www.wpftutorial.net/PasswordBox.html
I'm trying to handle the event when the close button of a Window is clicked:
// View Code
#Override
public void attachWindowListener(WindowListener listener) {
window.addWindowListener(listener);
}
// Presenter code
view.attachWindowListener(new WindowListener(){
public void windowHide(WindowEvent we) {
GWT.log("Window Event - Processing fields");
processFields();
}
});
However, the windowHide function seems to be not executed since I can't see the log I placed there.
How to properly handle that event?
How about
Window.addCloseHandler(
new CloseHandler<Window>()
{
public void onClose( CloseEvent<Window> windowCloseEvent )
{
// Do your worst here
}
} );
I usually put this in onModuleLoad() in my EntryPoint class.
Cheers,
Based on the information provided I would guess that either a.) the events you think are firing do not fire for the Window component (even if it seems like they should) or b.) the events are firing but in a different order than you expect.
For example, it's possible that a BrowserEvent or some other event is firing first as the window is being closed and the Window object's WindowEvent never fires. According to the API docs for GXT 2.x, the WindowEvent will fire on hide and deactivate but it does not specify that it fires on close. The GXT 3.0.x API doc is less clear on this point but I would assume the same behavior. Unfortunately Sencha does not provide good documentation on what events fire for a given component and in what order.
With that said, I have had some luck working through similar issues to this by using a debug class which outputs all the events on a component to which it is attached. This may shed some light on which events are firing and their order of execution, and you may find an optimal event to which you can attach your processFields() method.
For a good example of a debugger class, see this answer from a related post: https://stackoverflow.com/a/2891746/460638. It also includes an example of how to attach the debugger to your component.
API Doc for Window, GXT 2.x: http://dev.sencha.com/deploy/gxt-2.2.5/docs/api/com/extjs/gxt/ui/client/widget/Window.html
API Doc for Window, GXT 3.0.x: http://dev.sencha.com/deploy/gxt-3.0.0/javadoc/gxt/com/sencha/gxt/widget/core/client/Window.html
This worked:
window.addListener(Events.Hide, new Listener<ComponentEvent>() {
#Override
public void handleEvent(ComponentEvent be) {
// Do stuff
}
});
My app is a typical GWT application, it has a navigation bar, when click one bar item, the place will be changed and the app will find corresponding activity for that place(done in MasterActivityMapper), then call activity.start(). During the init of activities, the corresponding views were also created. When my app first starts, it will by default select the first navigation bar item.
public class MasterActivitiesMapper implements Activity
{
public Activity getActivity( Place place )
{
if(place equals place1)
{
Activity1 a1= new Activity1();
return a1;
}
else if(place equals place2)
{
Activity1 a2= new Activity2();
return a2;
}
else if(...)
{
....
}
}
}
My app works well except that the initial download size is too large, it will takes 10 seconds to load. I have to use code split the solve this problem.
I read the doc
https://developers.google.com/web-toolkit/doc/latest/DevGuideCodeSplitting
However still can not figure out where/how to split the code, could anybody has experience with this help?
Activity.start, being asynchronous by nature, seems like a good place to put a GWT.runAsync.
There's also the possibility of returning an activity async proxy from your ActivityMapper. See http://code.google.com/p/google-web-toolkit/issues/detail?id=5129 and https://gist.github.com/3038878 for some sample code.
I've been looking at a view examples of the typical "raise dialog from viewmodel" problem, noting 3 main solutions:
use attached behaviors
use a mediator pattern
use a service
I'm getting a bit bogged down though and struggling to find a solution that easily fits into my problem space - which is a very simple file copy problem:
My viewmodel is processing a loop (copying a list of files)
When a file already exists at the destination I need to raise a modal dialog to get confirmation to replace
The vm needs to wait for and receive confirmation before continuing
The "modal dialog" is actually not a new window but a hidden overlay in my MainWindow, as per http://www.codeproject.com/KB/WPF/wpfmodaldialog.aspx (thanks Ronald!)
I'm mostly there but the biggest struggles I have are:
- how to pause the loop in the viewmodel while it waits for input
- how to get input back to the viewmodel within the loop so it can carry on
So far I'm leaning towards the service solution because it seems a direct method call with a return that the vm must wait for. However, it does mean the service needs to tie directly to the view in order to make an element visible?
If anyone can post some simple code that deals directly with this problem I (and the net) would be very happy! Thanks!
For example, you have a service called IDialogService with the following interface:
public interface IDialogService
{
bool ConfirmAction(string title, string confirmationText);
}
As you mentioned, in order for the service to be able to show the actual dialog it needs to have a reference to the view that will show the actual overlay element. But instead of directly referencing the view I prefer to reference it via an interface. Lets call it ICanShowDialog and it will have the following members:
public interface ICanShowDialog
{
void ShowDialog(object dialogContent);
void HideDialog();
}
This interface will be implemented by your view that owns the dialog overlay (e.g. your main window).
Now the interesting part: suspending the code execution while the dialog is shown. First of all, I would recommend you not to use overlay elements but use usual windows if possible. Then you will not have that problem. You can style the dialog window so it will look just like the overlay element.
Anyway, if you still want to use overlay elements then you can do the following trick to suspend the code execution:
Here is pseudo code of the ConfirmAction method of the IDialogService inteface:
public bool ConfirmAction(string title, string confirmationText)
{
ConfirmationDialogView dialogView = new ConfirmationDialogView(title, confirmationText);
DialogShower.ShowDialog(dialogView); // DialogShower is of type ICanShowDialog
while (!dialogView.ResultAvailable)
{
DispatcherUtils.DoEvents();
}
DialogShower.HideDialog();
return dialogView.Result;
}
Here is the code of DispatcherUtils.DoEvents() (that was taken from here: http://dedjo.blogspot.com/2007/08/how-to-doevents-in-wpf.html):
public static class DispatcherUtils
{
public static void DoEvents()
{
DispatcherFrame f = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Background,
(SendOrPostCallback)delegate(object arg) {
DispatcherFrame fr = arg as DispatcherFrame;
fr.Continue=True;
}, f);
Dispatcher.PushFrame(frame);
}
}
But I must warn you. Using DoEvents can result in some subtle bugs caused by inner dispatcher loops.
As an alternative to suspending the code execution while a dialog is shown you can use callbacks:
public interface IDialogService
{
void ConfirmAction(string title, string confirmationText, Action<bool> dialogResultCallback);
}
But it will not be so convenient to use.