How can I transform method into an event? - c#

How do I make this method into an event?
BarcodeScannerRenderer.cs:
void IScanSuccessCallback.barcodeDetected(MWResult result)
{
if (result != null)
{
try
{
var scan = Element as BarcodeScannerModal;
if (scan == null)
return;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
And pass the value of result into another class, specifically in here:
(BarcodeScanner.cs)
public async Task<object[]> GetResult()
{
TaskCompletionSource<object[]> tcs = new TaskCompletionSource<object[]>();
scanPage.OnScanResult += async (result) =>
{
object[] scanResult = new object[2];
SharedAppSettings.Sounds.PlayBeep();
scanResult[0] = resultFinal.text;
scanResult[1] = resultFinal.typeText;
await PopupNavigation.PopAsync();
tcs.SetResult(scanResult);
};
return await tcs.Task;
}
If you ever wonder what type of Barcode Scanner I am using, it's Manatee Works Barcode Scanner.

This answer will probably have to be adapted to changes to the question, so do not consider it complete:
To raise an event you'd do something like this:
// Given you have a custom EventArgs class ...
// Define an event on which clients can register their handlers
public event EventHandler<BCDetectedEventArgs> BarcodeDetected;
// infoObject should probably be of the type what `scan` is.
protected virtual void OnBarcodeDetected( object infoObject )
{
// Check if there is at least one handler registered
var handler = BarcodeDetected;
if( handler != null )
{
handler(this, new BCDetectedEventArgs(infoObject));
}
}
void IScanSuccessCallback.barcodeDetected(MWResult result)
{
if (result != null)
{
try
{
var scan = Element as BarcodeScannerModal;
if (scan == null)
return;
else
OnBarcodeDetected( scan );
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
See also for reference https://msdn.microsoft.com/en-us/library/db0etb8x(v=vs.110).aspx
The part in BarcodeScanner.cs is a little more tricky because your snippet suggests a "polling" design. You would first have to adapt to register to the event from above snippet and act on the event in an appropriate handler method.

Related

WindowsAppSDK doesnt have ProtocolActivatedEventArgs

I am trying to handle protocol activation and as per docs I should handle all of that within OnLaunched method so that is what I am trying to do here, but Microsoft.Windows.AppLifecycle.ProtocolActivatedEventArgs doesnt exist.
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var activatedArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
var e = args.UWPLaunchActivatedEventArgs;
InitializeRootFrame(e);
if (activatedArgs.Kind is ExtendedActivationKind.Launch)
{
if (!e.PrelaunchActivated)
{
if (RootFrame.Content == null)
{
RootFrame.Navigate(typeof(LoginPage), e.Arguments);
}
Window.Current.Activate();
}
}
else //Launched by some other means other than normal launching
{
try
{
if (activatedArgs.Kind is ExtendedActivationKind.Protocol && activatedArgs is Microsoft.Windows.AppLifecycle.ProtocolActivatedEventArgs eventArgs)
{
//var a = activatedArgs.Data as ProtocolActivatedEventArgs;
var queryParameters = HttpUtility.ParseQueryString(activatedArgs.Data.Uri.Query);
PocessQueryForToken(queryParameters);
}
}
catch (Exception)
{
}
finally
{
RootFrame.Navigate(typeof(LoginPage));
Window.Current.Activate();
HasLaunched = true;
}
}
HasLaunched = true;
}
There is only a AppActivationArguments Class in the Microsoft.Windows.AppLifecycle NameSpace. So the behavior you got is expected because you are looking for a class that doesn't even exist.
Based on the document for AppActivationArguments, we could know that the activatedArgs we got contains a data object which has one of the following data types, depending on the activation type specified by the Kind property.
File ->IFileActivatedEventArgs
Protocol ->IProtocolActivatedEventArgs
StartupTask ->IStartupTaskActivatedEventArgs
The IProtocolActivatedEventArgs should be the thing that we are looking for. The document here-ProtocolActivatedEventArgs Class shows that this Class comes from the Windows.ApplicationModel.Activation Namespace.
So the code should looks like this:
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
var eventargs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
if (eventargs.Kind is ExtendedActivationKind.Protocol && eventargs.Data is Windows.ApplicationModel.Activation.ProtocolActivatedEventArgs)
{
ProtocolActivatedEventArgs ProtocolArgs = eventargs.Data as ProtocolActivatedEventArgs;
var uri = ProtocolArgs.Uri;
}
}

assigning event handlers for potentially long list of socket topics

I am listening to socket messages from Socket.io server in my C# cmd client application.
Once a message is received; I trigger a C# event for all event listeners in the C# application. The C# event listeners are specific to the socket topic.
My question is; is there a better way to assign the event handlers?...for 100s of possible topics?
public static class EventHub(){
string[] all_topics = { "topic1", "topic2", "topic3" };
public event EventHandler<TopicEventArgs> On_topic1_event ;
public event EventHandler<TopicEventArgs> On_topic2_event ;
public event EventHandler<TopicEventArgs> On_topic3_event ;
public static Go()
{
var socket = new SocketIO("http://localhost:11000/");
foreach (string topic in all_topics) {
//hookup socket with the topics to listen
socket.On(topic, response =>
{
var value = response.GetValue<int>(1);
//**HERE** Is there a better way of doing the following?
if (topic == "topic1" && On_topic1_event != null)
{
On_topic1_event (this, new TopicEventArgs(topic, value));
}
else if (topic == "topic2" && On_topic2_event != null)
{
On_topic2_event (this, new TopicEventArgs(topic, value));
}
else if (topic == "topic3" && On_topic3_event != null)
{
On_topic3_event (this, new TopicEventArgs (topic, value));
}
...
});
}
}
}
public class TopicEventArgs : EventArgs
{
public TopicEventArgs(string t, double v)
{
this.Value = v;
this.Topic = t;
}
public double Value { get; set; }
public string Topic { get; set; }
}
//usage
//function Go is called once in apps life cycle.
...
EventHub.Go()
...
i am going with this approach. handler.Invoke should call the proper event handler with the naming format i am following.
foreach (string topic in all_topics) {
//hookup socket with the topics to listen
socket.On(topic, response =>
{
var value = response.GetValue<int>(1);
//event handler methods signature 'On_[topic name]_event'
MethodInfo handler = thisType.GetMethod("On_"+topic.ToUpper() +"_event", BindingFlags.Public);
if (handler != null)
{
TopicEventArgs[] arg = { new TopicEventArgs(topic, value) };
handler.Invoke(this, arg);
}
});
}

Xamarin IMobileServiceTable Run Synchronously

Using the IMobileServiceTable interface, how can I call result of a method synchronously. E.g. GetTask method below :
public class ItemsManager {
IMobileServiceTable<Item> itemTable;
private ItemViewModel _itemViewModel = new ItemViewModel ();
public ItemsManager()
{
this.itemTable = App.client.GetTable<Item>();
App.SetItemsManager(this);
}
//This seems to just hang
public Item GetTask(string id, string barcode)
{
var qry = itemTable.Where(a => a.ItemID == id || a.BarCodeID == id);
return qry.Query.FirstOrDefault();
}
}
I'm trying to get the result via scan method, and extract the item record to another form :
async void OnProductScanClicked (object sender, EventArgs e)
{
var result = await BarCodes.Instance.Read ();
if (!result.Success) {
await this.DisplayAlert ("Scan Failed", "Failed to get barcode", "OK");
} else {
var msg = String.Format ("Barcode : {0} - {1}", result.Format, result.Code);
App.SetItemsManager(new ItemsManager());
var item = App.ItemManager.GetTask(result.Code, result.Format.ToString());
if (item == null) {
await this.DisplayAlert ("Item Not Found!", msg, "OK");
}
else {
var myPage = new ItemsXaml();
myPage.BindingContext = item;
await Navigation.PushModalAsync (myPage);
}
}
}
I am just new to this stuff, and now have figure out on how to this. We just have to add the await method when calling any asynchronous function.

try catch inside a catch clause

I'm currently loading images in different ways like this:
try {
// way 1
}
catch
{ // way 1 didn't work
try {
// way 2
}
catch
{
// etc.
}
}
I was wondering if there was a cleaner way to do this. Currently it's not a problem but if i add a few more ways it's going to get messy.
Note that the method loading the image is also in a try catch in the same way because it might not be an image.
It's basically trying a bunch of stuff to figure out what it is you dragged into the application.
You can write a method that accepts any number of delegates, attempting all of them and stopping after one of them runs successfully. This abstracts the exception handling into one place, and avoids all of the repetition:
public static void AttemptAll(params Action[] actions)
{
var exceptions = new List<Exception>();
foreach (var action in actions)
{
try
{
action();
return;
}
catch (Exception e)
{
exceptions.Add(e);
}
}
throw new AggregateException(exceptions);
}
This allows you to write:
AttemptAll(Attempt1, Attempt2, Attempt3);
If the methods compute a result you can create a second overload to handle that as well:
public static T AttemptAll<T>(params Func<T>[] actions)
{
var exceptions = new List<Exception>();
foreach (var action in actions)
{
try
{
return action();
}
catch (Exception e)
{
exceptions.Add(e);
}
}
throw new AggregateException(exceptions);
}
Assuming the "different ways" to load the image all throw an exception upon failure, you could iterate through the different ways, until one succeeds. The example below uses a Function<Image> to show a parameterless function that returns an image upon success. In your concrete example, you probably also have parameters into your function.
List<Function<Image>> imageLoaders = LoadTheListSomehow();
foreach (var loader in imageLoaders)
{
try
{
var image = loader();
break; // We successfully loaded the image
}
catch (Exception ex)
{
// Log the exception if desired
}
}
The nesting there does look unnecessary. I would isolate each way of loading an image into its own private method, and then called these methods as delegates in a loop, like this:
private static MyImage LoadFirstWay(string name) {
return ...
}
private static MyImage LoadSecondWay(string name) {
return ...
}
private static MyImage LoadThirdWay(string name) {
return ...
}
...
public MyImage LoadImage(string name) {
Func<string,MyImage>[] waysToLoad = new Func<string,MyImage>[] {
LoadFirstWay
, LoadSecondWay
, LoadThirdWay
};
foreach (var way in waysToLoad) {
try {
return way(name);
} catch (Exception e) {
Console.Error("Warning: loading of '{0}' failed, {1}", name, e.Message);
}
}
return null;
}

how do you implement Async Operations in C# and MVVM?

hi what is the easiest way to implement asynch operations on WPF and MVVM, lets say if user if user hits enter when on a field i want to launch a command and then return back while a thread will do some search operations and then come back and update the properties so notification can update the bindings.
thanks!
Rob Eisenberg showed a really clean implementation of running async operations in MVVM during his MIX10 talk. He has posted the source code on his blog.
The basic idea is that you implement the command as returning an IEnumerable and use the yield keyword to return the results. Here is a snippet of code from his talk, which does a search as a background task:
public IEnumerable<IResult> ExecuteSearch()
{
var search = new SearchGames
{
SearchText = SearchText
}.AsResult();
yield return Show.Busy();
yield return search;
var resultCount = search.Response.Count();
if (resultCount == 0)
SearchResults = _noResults.WithTitle(SearchText);
else if (resultCount == 1 && search.Response.First().Title == SearchText)
{
var getGame = new GetGame
{
Id = search.Response.First().Id
}.AsResult();
yield return getGame;
yield return Show.Screen<ExploreGameViewModel>()
.Configured(x => x.WithGame(getGame.Response));
}
else SearchResults = _results.With(search.Response);
yield return Show.NotBusy();
}
Hope that helps.
How about a BackgroundWorker instance to call your command on the VM ?
Update:
Scratch the above suggestion.. There's an online video on MVVM by Jason Dolinger.. I recommend you take a look at that. It's a cleaner way where the view is thin/ does not hold any threading code.
To summarize:
the VM ctor caches the Dispatcher.CurrentDispatcher object (main thread).
when updating the backing store (results), use
_dispatcher.BeginInvoke( () => _results.AddRange( entries) ) so that the UI is updated correctly.
In Shawn Wildermuth's MSDN Article he did something like this:
check out the article here:
http://msdn.microsoft.com/en-us/magazine/dd458800.aspx
and his more recent blog post here:
http://wildermuth.com/2009/12/15/Architecting_Silverlight_4_with_RIA_Services_MEF_and_MVVM_-_Part_1
public interface IGameCatalog
{
void GetGames();
void GetGamesByGenre(string genre);
void SaveChanges();
event EventHandler<GameLoadingEventArgs> GameLoadingComplete;
event EventHandler<GameCatalogErrorEventArgs> GameLoadingError;
event EventHandler GameSavingComplete;
event EventHandler<GameCatalogErrorEventArgs> GameSavingError;
}
with an implementation like this:
public class GameCatalog : IGameCatalog
{
Uri theServiceRoot;
GamesEntities theEntities;
const int MAX_RESULTS = 50;
public GameCatalog() : this(new Uri("/Games.svc", UriKind.Relative))
{
}
public GameCatalog(Uri serviceRoot)
{
theServiceRoot = serviceRoot;
}
public event EventHandler<GameLoadingEventArgs> GameLoadingComplete;
public event EventHandler<GameCatalogErrorEventArgs> GameLoadingError;
public event EventHandler GameSavingComplete;
public event EventHandler<GameCatalogErrorEventArgs> GameSavingError;
public void GetGames()
{
// Get all the games ordered by release date
var qry = (from g in Entities.Games
orderby g.ReleaseDate descending
select g).Take(MAX_RESULTS) as DataServiceQuery<Game>;
ExecuteGameQuery(qry);
}
public void GetGamesByGenre(string genre)
{
// Get all the games ordered by release date
var qry = (from g in Entities.Games
where g.Genre.ToLower() == genre.ToLower()
orderby g.ReleaseDate
select g).Take(MAX_RESULTS) as DataServiceQuery<Game>;
ExecuteGameQuery(qry);
}
public void SaveChanges()
{
// Save Not Yet Implemented
throw new NotImplementedException();
}
// Call the query asynchronously and add the results to the collection
void ExecuteGameQuery(DataServiceQuery<Game> qry)
{
// Execute the query
qry.BeginExecute(new AsyncCallback(a =>
{
try
{
IEnumerable<Game> results = qry.EndExecute(a);
if (GameLoadingComplete != null)
{
GameLoadingComplete(this, new GameLoadingEventArgs(results));
}
}
catch (Exception ex)
{
if (GameLoadingError != null)
{
GameLoadingError(this, new GameCatalogErrorEventArgs(ex));
}
}
}), null);
}
GamesEntities Entities
{
get
{
if (theEntities == null)
{
theEntities = new GamesEntities(theServiceRoot);
}
return theEntities;
}
}
}

Categories