Caliburn Micro: taking photo in Mango - windows-phone-7

I'm trying to use a task launcher in WP7.1 Mango with the latest version of Caliburn Micro, but my code is not getting called back once the task has completed. Probably I'm doing something stupid somewhere, but I cannot see where. Here is what I did for a sample repro application you can download from:
http://www.filesonic.com/file/2750397005/PhoneTaskTest.zip
1) create a new WP7.1 application;
2) add a Lib folder in the solution, add there CM dll's, and add a reference to them;
3) change the generated files as specified by CM documentation and add a bootstrapper.
Now up to this point everything is OK and the application starts with no issues. I then do the following for taking a photo:
4) add a button in the main page to the view and a corresponding method in its VM, named TakePhoto.
5) change the VM as follows:
a) add a readonly IEventAggregator member injected in the constructor;
b) add OnActivate/OnDeactivate overrides to let the aggregator subscribe and unsubscribe this VM;
c) add the TakePhoto method which is just:
_aggregator.RequestTask<CameraCaptureTask>();
d) derive the VM from interface IHandle<TaskCompleted<CameraCaptureTask>> and implement it:
public void Handle(TaskCompleted<CameraCaptureTask> message)
{
if (message.Result.TaskEventArgs.TaskResult != TaskResult.OK) return;
SetPhoto(message.Result.TaskEventArgs.ChosenPhoto);
}
Now, when I click the button the camera task starts in the emulator and I can take a photo; then I'm taken back to my application, but nothing happens and my Handle method is NEVER called. You can just place a breakpoint there to confirm this.
So, what I'm doing wrong here?

You need to handle TaskCompleted<PhotoResult> instead of TaskCompleted<CameraCaptureTask>. Because Caliburn.Micro creates theTaskCompleted<T> message with the event args of the Task's Completed event which is in the case of CameraCaptureTask is PhotoResult. So you should implement IHandle<TaskCompleted<PhotoResult>> and your Handle method should look like this
public void Handle(TaskCompleted<PhotoResult> message)
{
if (message.Result.TaskResult != TaskResult.OK) return;
SetPhoto(message.Result.ChosenPhoto);
}

Related

Prism Xamarin OnNavigatedTo will not execute a function

I have my application designed using Xamarin Prism .
I have a command that should be executed when the user navigate to this given page .
it runs in a different project , but when I rewrote the same code , it will not run .
I compared the codes and almost identical . however , it still will not run in this code .
first I defined the command :
public IAsyncCommand InitCommand { get; }
in my view model constructor I have this code :
InitCommand = new AsyncCommand(InitAsync);
and this is my InitAsync method :
private async Task InitAsync()
{
await GetTransactionsByWallet(WalletId).ConfigureAwait(false); ;
}
and in my OnNavigatedTo part of prism , i have this code :
public void OnNavigatedTo(INavigationParameters parameters)
{
WalletId = parameters.GetValue<IWallets>("wallet").Id;
InitCommand.ExecuteAsync();
}
note :
InitCommand.ExecuteAsync(); will not execute even if i put a stop at it to debug it , the debugger also wont stop to it .
im using AsyncAwaitBestPractices.MVVM for the creation of the command .
Any reason you have decided to run the command rather than the method directly? i.e. instead of InitCommand.ExecuteAsync(); why not just await InitAsync().
Note: you can make OnNavigatedTo an async method. And since it is an eventhandler (the events being fired during navigation), async void is allowed - https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
Here - https://forums.xamarin.com/discussion/91897/prism-calling-async-method-in-onnavigatedto-or-any-of-the-methods-from-inavigationaware
As mentioned by Brian Lagunas (manager of the Prism Library)
But if that option doesnt sound good - another option is to run the method during the "Loaded" event of the view. These are not workarounds, these are the proper mvvm ways to do this. For running the method on loaded, you have two ways of doing it -
(1) Use Xaml Behavior Library's CallMethodAction or
(2) Use Prism's inbuilt InvokeCommandAction with the XAML Interactivity.

EchoBot: How does control flow from BotController to EchoBot

I am looking at the EchoBot sample and trying to understand it. I see that BotController is mapped to api/messages and HttpPost which in turn invokes Adapter.ProcessAsync. But how does this translate into EchoBot.OnMessageActivityAsync call? I tried to set up a breakpoint and see the call stack but that doesn't help ( see attached screenshot).
I understand BotFrameworkHttpAdapter is invoked via dependency injection. But I don't know how we end up in EchoBot eventually.
To find the answer to this you really have to dive into the source code, so I hope you've got your scuba diving gear because we're going deep.
Step 1
Inside the BotController.cs file the following piece of code is called:
await Adapter.ProcessAsync(Request, Response, Bot);
which calls the ProcessAsync method on the IBotFrameworkHttpAdapter interface.
Step 2
Inside the Startup.cs file we have the following line:
services.AddSingleton<IBotFrameworkHttpAdapter, BotFrameworkHttpAdapter>();
which says that every time we ask for an IBotFrameworkHttpAdapter, provide the same instance of BotFrameworkHttpAdapter - essentially a static variable, you can read more about dependency injection service lifetimes here.
Step 3
Inside the Microsoft.Bot.Builder package we have the implementation for the ProcessAsync method, that can for our purposes be reduced to the following line:
var invokeResponse = await ProcessActivityAsync(authHeader, activity, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);
which calls ProcessActivityAsync which is another function that lives in this library - the important part here is the bot.OnTurnAsync parameter being passed in.
Step 5
Also inside the Microsoft.Bot.Builder package is the implementation for ProcessActivityAsync:
return await ProcessActivityAsync(claimsIdentity, activity, callback, cancellationToken).ConfigureAwait(false);
which calls an overload of the same method, but before we move on from here, the callback parameter is the bot.OnTurnAsync parameter that was passed through before.
Step 6
The overload of ProcessActivityAsync is also implemented inside the Microsoft.Bot.Builder package, and can be simplified to this line:
await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);
where callback is bot.OnTurnAsync.
Step 7
Digging deeper still we find the implementation of the RunPipelineAsync method inside of the Microsoft.Bot.Builder package which is were things start to get a bit fuzzy... Theoretically we want to fall through to the else block where the callback (i.e. bot.OnTurnAsync) is called:
// Call any registered Middleware Components looking for ReceiveActivityAsync()
if (turnContext.Activity != null)
{
// Other code
}
else
{
// call back to caller on proactive case
if (callback != null)
{
await callback(turnContext, cancellationToken).ConfigureAwait(false);
}
}
However, back in Step 6 we also had this line:
using (var context = new TurnContext(this, activity))
where the context is created, and the activity property is initialised. This same context is pass through to the RunPipelineAsync call, which means that we will not fall through to the else block...
But there are the following comment on the RunPipelineAsync method:
/// <param name="callback">A callback method to run at the end of the pipeline.</param>
and inside the remarks section:
...Once control reaches the end of the pipeline, the adapter calls
the <paramref name="callback"/> method...
So I believe is it safe to say that our callback method is being executed which means that we continue by bubbling back up the chain to resolve the function that callback maps to (bot.OnTurnAsync).
Step 8
In BotController we pass in an instance of IBot to the ProcessAsync method, and in Startup we wire up all requests for an IBot to return an instance of EchoBot like so:
// Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
services.AddTransient<IBot, EchoBot>();
The EchoBot implementation inherits from the ActivityHandler class:
public class EchoBot : ActivityHandler
Step 9
The ActivityHandler class provides a default implementation for the OnTurnAsync method which I will simplify to:
switch (turnContext.Activity.Type)
{
case ActivityTypes.Message:
return OnMessageActivityAsync(new DelegatingTurnContext<IMessageActivity>(turnContext), cancellationToken);
// Other cases
}
which the OnMessageActivityAsync method on the same class that has an implementation that returns a completed task, i.e. is a no-op, however it is a virtual method - classes which inherit ActivityHandler can provide their own implementation.
Step 10
A custom implementation for OnMessageActivityAsync is provided inside the EchoBot class:
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken);
}
where the user's input is echoed back to them, and thus our journey ends.
Regarding Step 7, the Microsoft team are pretty active on SO for things tagged with botframework so it might be best to get #mdrichardson or #tdurnford to clarify what happens here.
As an aside in Visual Studio you can debug some library code by enabling the following option:
Tools --> Options --> Debugger
Uncheck "Enable Just my Code"
Also if you enable navigation to decompiled sources (you will have to accept a legal notification popup) by doing this:
Tools --> Options --> Text Editor --> C# --> Advanced
Check "Enable navigation to decompiled sources"
You will be able to inspect the source code of external packages within Visual Studio itself.

Winforms Application Fails To Launch [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have a winforms application that is installed on multiple computers. Most of the time it works perfectly but for a small subset of users the application fails to launch. The only resolution I have found for this issue is to reinstall the application on the users machine.
I have included screenshots below showing the application working after a successful launch and also a screenshot showing what the user sees when the application fails
Normal Launch:
Failed Launch:
When the application fails, the startup form does not get rendered at all. On the users desktop there is nothing visible at all and the program is not outside of any visible area.
If anyone could provide answers or insight into the following questions it would be much appreciated.
What could cause this problem?
Windows or program related?
How could this be fixed?
I have included code snippets from the startup form below
Starting code:
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.Run(new Timelord());
}
public Timelord()
{
this.InitializeComponent();
this.BringToFront();
this.Focus();
// Displays a date and gets the version of the program
lblDate.Text = DateTime.Now.ToShortDateString();
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
if (ApplicationDeployment.IsNetworkDeployed)
{
lblVersion.Text = string.Format("v{0}", ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString(4));
}
// Loads the comboboxes for selection
this.loadComboUser();
this.loadComboCompany();
this.loadComboTick();
}
I think what is happening is that there is an error being thrown in your Timelord constructor under certain conditions. Since Timelord is the "startup" object for your application, a failure to create its instance properly would cause serious problems. Here is what I would recommend doing to identify those conditions, and to eliminate the issue with the form only being partially created.
I am assuming based on your comment about the program reading from a database that one or more of the following methods perform data access calls to a database
this.loadComboUser();
this.loadComboCompany();
this.loadComboTick();
You typically want to avoid method calls, ESPECIALLY data access calls in a constructor. There are many reasons for this that I won't list here, but this other stackoverflow article explains some of them.
Is it OK to put a database initialization call in a C# constructor?
To correct these issues, implement an eventhandler for the load event and move all of your Timelord constructor code into the Load event handler. The Form.Load event fires after the constructor is complete but before a form is displayed for the first time.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.form.load?view=netframework-4.7.2
Here is how I would recommend restructuring your Timelord object.
public Timelord()
{
this.InitializeComponent();
}
Private Sub Timelord_Load(sender As Object, e As EventArgs) Handles MyBase.Load
{
Try
{
this.BringToFront();
this.Focus();
// Displays a date and gets the version of the program
lblDate.Text = DateTime.Now.ToShortDateString();
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
if (ApplicationDeployment.IsNetworkDeployed)
{
lblVersion.Text = string.Format("v{0}", ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString(4));
}
// Loads the comboboxes for selection
this.loadComboUser();
this.loadComboCompany();
this.loadComboTick();
}
Catch(Exception ex)
{
MessageBox.Show($"The following error occurred in the Timelord constructor {Environment.NewLine}{ex.Message}")
}
}
Making this change will allow the Timelord constructor to completely create the object, then the Load event will run and load any data into the UI. This way, if an error occurs, you will have at least completely created the Timelord Form and can catch the error.
What could cause this problem?
Your startup object (Timelord()) throwing an error in the constructor, therefore not properly creating object.
Windows or program related?
Program related
How could this be fixed?
Separating your Forms logic so that the only code in the constructor is your instantiation logic.
Implementing Try/Catch blocks to trap errors

SolutionEvents for Visual studio 2010 addin does not fire

I'm building an visual studio 2010 addin and trying to hook into an event when the solution is loaded.
Basically what I have found is that SolutionEvents.Opened seems to be what I'm looking for, however listening to it in OnConnection does not seem to be working:
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
applicationObject = (DTE2)application;
var outputWindow = (OutputWindow)applicationObject.Windows.Item(Constants.vsWindowKindOutput).Object;
outputWindowPane = outputWindow.OutputWindowPanes.Add("My Pane");
applicationObject.Events.SolutionEvents.Opened += SolutionEventsOnOpened;
outputWindowPane.OutputString("Connected");
}
private void SolutionEventsOnOpened()
{
outputWindowPane.OutputString("SolutionEventsOnOpened");
}
The only thing outputed is "Connected".
I have tried to listen to SolutionItemsEvents.ItemAdded and SolutionEvents.ProjectAdded and also they do not fire.
Should I init the events elsewhere? (Note I have R# installed, perhaps it is knowed to cause issues?)
Found the solution here: http://blogs.microsoft.co.il/blogs/kolbis/archive/2007/11/22/hooking-up-to-the-solution-events.aspx
Basically, you need to declare members at your add-in class scope for the SolutionEvents and Events variables, and assign them, and then reference the eventhandlers through that. E.g.
private Events2 m_events;
private SolutionEvents m_solutionEvents;
then in the OnConnection handler (when your plugin gets initialised) do this:
m_application = Application as DTE2;
m_events = (Events2)m_application.Events;
m_solutionEvents = m_events.SolutionEvents;
and finally, wire up the solution Opened/AfterClosing events, as follows:
m_solutionEvents.Opened += m_openSolution;
m_solutionEvents.AfterClosing += m_closeSolution;
Then the events will fire.
I presume the reason for doing this is because otherwise the Events/SolutionEvents objects get changed or GC'd (or both ;-).
HTH
With VS2010, when opening a .sln file that leads to start a new VS2010 instance, it is worth noting that SolutionEvents.Opened is fired before EventsObj.OnStartupComplete is fired. So if you register SolutionEvents.Opened during EventsObj.OnStartupComplete it won't fire in this situation.
As far as I know all VS versions post-2010 [2012-2019] fire SolutionEvents.Opened after EventsObj.OnStartupComplete is fired.

Can you invoke a control rather than launch an app for coded ui tests?

I have code such that:
[CodedUITest]
public class CodedUITest1
{
[TestMethod]
public void CodedUITestMethod1( )
{
using(var dlg = new MyWinForm( ))
{
dlg.Show();
System.Threading.Thread.Sleep(2000);
this.UIMap.AssertMethod1( );
this.UIMap.RecordedMethod1( );
this.UIMap.AssertMethod2( );
}
}
}
The code was running fine when I manually launched the app(before invoking the test) without the using clause to directly create the control.
I'd like to just use a reference to create an instance of the control and go from there instead of relying on trying to determine a path to the executable and opening it. The app just gets stuck with a ContextSwitchDeadlock.
Is there a way to do coded-Ui tests without doing a process launch? (using the reference and creating the control in the test code) or is there something wrong with the way I'm trying to do it?
It might be possible if you invoke the coded ui test portions (this.UIMap...) on a separate thread. But the way you have it now, they are both on the same thread, so you are going to get deadlocked.

Resources