Subscribe to DisplayAlert in Xamarin.Forms - testing

I'd like to get notified whenever DisplayAlert is called somewhere in my app. The Xamarin.Forms source code suggests to use the MessagingCenter, since it is using it to send a message within DisplayAlert():
MessagingCenter.Send(this, AlertSignalName, args);
But I haven't been able to receive anything, yet. This is one of the lines I tried so far:
MessagingCenter.Subscribe<Page>(this, Page.AlertSignalName, arg => {
Console.WriteLine("Message received: " + arg);
});
Is this the right direction? Or do you have an alternative solution? I'd even consider some hacky reflection-based approach, since I need it for testing purposes only.

This works for me:
MessagingCenter.Subscribe<Page, Xamarin.Forms.Internals.AlertArguments>(this, Page.AlertSignalName, (obj, obj1) => {
int aa = 0;
});
But it is raised when DisplayAlert is displayed. (I think it's correct...)
This is my page:
using System;
using Xamarin.Forms;
namespace Test
{
public class MyPage : ContentPage
{
public MyPage()
{
Button b = new Button {Text = "Press" };
b.Clicked += async (object sender, EventArgs e) => {
await DisplayAlert("Attention", "AAA", "Ok");
MessagingCenter.Send<MyPage>(this, "AAA");
};
Content = new StackLayout
{
Children = {
new Label { Text = "Hello ContentPage" },
b
}
};
MessagingCenter.Subscribe<MyPage>(this, "AAA", (obj) => {
int aa = 0;
});
MessagingCenter.Subscribe<Page, Xamarin.Forms.Internals.AlertArguments>(this, Page.AlertSignalName, (obj, obj1) => {
int aa = 0;
});
}
}
}

In Xamarin source test code (namespace Xamarin.Forms.Core.UnitTests), it's used in a strongly typed way like that:
[Test]
public void DisplayAlert ()
{
var page = new ContentPage ();
AlertArguments args = null;
MessagingCenter.Subscribe (this, Page.AlertSignalName, (Page sender, AlertArguments e) => args = e);
var task = page.DisplayAlert ("Title", "Message", "Accept", "Cancel");
Assert.AreEqual ("Title", args.Title);
Assert.AreEqual ("Message", args.Message);
Assert.AreEqual ("Accept", args.Accept);
Assert.AreEqual ("Cancel", args.Cancel);
bool completed = false;
var continueTask = task.ContinueWith (t => completed = true);
args.SetResult (true);
continueTask.Wait ();
Assert.True (completed);
}
So this should do it:
MessagingCenter.Subscribe(this, Page.AlertSignalName, (Page sender, AlertArguments args) =>
{
Console.WriteLine("Message received: " + args.Message);
});

Related

error CS0103: The name 'ModelHelper' does not exist in the current context

I am trying to implement Object detection on HoloLens2 using Microsoft Custom Vision.
I have been following the tutorial (https://learn.microsoft.com/en-us/archive/blogs/appconsult/23535)
but faced with this error..
error CS0103: The name 'ModelHelper' does not exist in the current context
the codes are as below.
what is this ModelHelper for?
and is there anything that i have to add to use it?
using System;
using System.Linq;
using System.Threading.Tasks;
#if UNITY_WSA && !UNITY_EDITOR
using Windows.Media.Capture;
using Windows.Media.Capture.Frames;
using Windows.Media.MediaProperties;
public class ScanEngine
{
public TimeSpan PredictionFrequency = TimeSpan.FromMilliseconds(400);
private MediaCapture CameraCapture;
private MediaFrameReader CameraFrameReader;
private Int64 FramesCaptured;
IUnityScanScene UnityApp;
public ScanEngine()
{
}
public async Task Inititalize(IUnityScanScene unityApp)
{
UnityApp = unityApp;
await InitializeCameraCapture();
await InitializeCameraFrameReader();
}
private async Task InitializeCameraCapture()
{
CameraCapture = new MediaCapture();
MediaCaptureInitializationSettings settings = new
MediaCaptureInitializationSettings();
settings.StreamingCaptureMode = StreamingCaptureMode.Video;
await CameraCapture.InitializeAsync(settings);
}
private async Task InitializeCameraFrameReader()
{
var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();
MediaFrameSourceGroup selectedGroup = null;
MediaFrameSourceInfo colorSourceInfo = null;
foreach (var sourceGroup in frameSourceGroups)
{
foreach (var sourceInfo in sourceGroup.SourceInfos)
{
if (sourceInfo.MediaStreamType == MediaStreamType.VideoPreview
&& sourceInfo.SourceKind == MediaFrameSourceKind.Color)
{
colorSourceInfo = sourceInfo;
break;
}
}
if (colorSourceInfo != null)
{
selectedGroup = sourceGroup;
break;
}
}
var colorFrameSource = CameraCapture.FrameSources[colorSourceInfo.Id];
var preferredFormat = colorFrameSource.SupportedFormats.Where(format =>
{
return format.Subtype == MediaEncodingSubtypes.Argb32;
}).FirstOrDefault();
CameraFrameReader = await CameraCapture.CreateFrameReaderAsync(colorFrameSource);
await CameraFrameReader.StartAsync();
}
public void StartPullCameraFrames()
{
Task.Run(async () =>
{
for (; ; ) // Forever = While the app runs
{
FramesCaptured++;
await Task.Delay(PredictionFrequency);
using (var frameReference = CameraFrameReader.TryAcquireLatestFrame())
using (var videoFrame = frameReference?.VideoMediaFrame?.GetVideoFrame())
{
if (videoFrame == null)
{
continue; //ignoring frame
}
if (videoFrame.Direct3DSurface == null)
{
videoFrame.Dispose();
continue; //ignoring frame
}
try
{
await
ModelHelper.EvaluateVideoFrameAsync(videoFrame).ConfigureAwait(false);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
}
}
}
});
}
}
#endif

signalr with sqldepdency firing multiple times for each browser instance

I am having a asp.net mvc app with vs2013 and .net framwork 4.5.1 which should notify users when a certain field gets updated and for a certain recordID.
Everything works fine when I have a single instance of the browser open, but when i open another tab or browser either on the same machine or on the different machine it fires the sqldepdencychange event multiple times.
Below is my hub code
public class MessagesHub : Hub
{
private static string conString = ConfigurationManager.ConnectionStrings["FleetLink_DB"].ToString();
private static string hostName = "";
public static void SendMessages(string hName)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessagesHub>();
hostName = hName;
context.Clients.Group(hostName).updateMessages(hName);
}
public Task leaveGroup(string hName)
{
return Groups.Remove(Context.ConnectionId, hName);
}
public Task joinGroup(string hName)
{
return Groups.Add(Context.ConnectionId, hName);
}
}
Below is my signalr script file
$(function () {
var dialog, form
// Declare a proxy to reference the hub.
var notifications = $.connection.messagesHub;
//debugger;
//Create a function that the hub can call to broadcast messages.
notifications.client.updateMessages = function (hName) {
alert("testing");
getoneMessages(hName)
};
$.connection.hub.logging = true;
$.connection.hub.start().done(function () {
var hostName = getUrlVars()["System_Name"];
notifications.server.joinGroup(hostName);
}).fail(function (e) {
alert(e);
});
});
function getUrlVars() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function getoneMessages(hName) {
var tbl = $('#selectable');
//alert('mesgID=' + mesgID)
//var tbl = $('#selectable');
$.ajax({
url: '/controller/view',
cache: false,
contentType: 'application/html ; charset:utf-8',
type: 'GET',
dataType: 'html'
}).success(function (result) {
//alert(result);
tbl.empty().append(result);
}).error(function (exception) {
//alert('failed= ' + exception);
});
}
window.onbeforeunload = function (e) {
var hostName = getUrlVars()["System_Name"];
notifications.server.joinGroup(hostName);
$.connection.hub.stop();
};
Below is my partialview code along with the definition for RegisterForNotification and depdendency_onchange event
public PartialViewResult SignalRTesterPartialView()
{
/...COde not included for brevity..../
RegisterForNotifications(ID);
}
public void RegisterForNotifications(int mID)
{
var efConnectionString = ConfigurationManager.ConnectionStrings["DB"].ConnectionString;
var builder = new EntityConnectionStringBuilder(efConnectionString);
var regularConnectionString = builder.ProviderConnectionString;
string commandText = null;
commandText = "select ID,Status,Name from tblABC where ID=" + strID;
using (SqlConnection connection = new SqlConnection(regularConnectionString))
{
using (SqlCommand command = new SqlCommand(commandText, connection))
{
connection.Open();
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
// NOTE: You have to execute the command, or the notification will never fire.
var reader = command.ExecuteReader();
}
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change && e.Info== SqlNotificationInfo.Update)
{
MessagesHub.SendMessages(hName);
}
RegisterForNotifications(1012);
}
Not sure why it is firing the sendmessages multiple times with each additional browser instance that I open. Any pointers would be helpful!
remove EventHandler when you done with it
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change && e.Info== SqlNotificationInfo.Update)
{
MessagesHub.SendMessages(hName);
}
//remove event handler
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= new OnChangeEventHandler(dependency_OnChange);
RegisterForNotifications(1012);
}

GridView: Get Index on Drop Event

How do I get the index or position where a GridViewItem is being dropped inside the OnDrop event of the GridView? As I have read around that it is possible with GridView.ItemContainerGenerator.ContainerFromItem(item) but for me ItemContainerGenerator is null.
This is my current code:
void gridMain_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
var item = e.Items.First();
var source = sender;
e.Data.Properties.Add("item", item);
e.Data.Properties.Add("source", sender);
}
void gridMain_Drop(object sender, DragEventArgs e)
{
var item = e.Data.Properties.Where(p => p.Key == "item").Single();
object source;
e.Data.Properties.TryGetValue("source", out source);
var s = ((GridView)source).ItemContainerGenerator.ContainerFromItem(item);
}
Any hint or suggestion will be really helpful.
Use GetPosition method of DragEventArgs to find the position where item was dropped and then calculate the actual index, see code snippet below for the handler. Similar question was asked here using this MSDN example as an answer (Scenario 3).
private void GridView_Drop(object sender, DragEventArgs e)
{
GridView view = sender as GridView;
// Get your data
var item = e.Data.Properties.Where(p => p.Key == "item").Single();
//Find the position where item will be dropped in the gridview
Point pos = e.GetPosition(view.ItemsPanelRoot);
//Get the size of one of the list items
GridViewItem gvi = (GridViewItem)view.ContainerFromIndex(0);
double itemHeight = gvi.ActualHeight + gvi.Margin.Top + gvi.Margin.Bottom;
//Determine the index of the item from the item position (assumed all items are the same size)
int index = Math.Min(view.Items.Count - 1, (int)(pos.Y / itemHeight));
// Call your viewmodel with the index and your data.
}
EDIT: Please, consider this as just a prototype. I tried it and it has worked properly, but you may revise it according to your scenario (tweak delay timeout, differentiate more TaskCompletionSource at once, etc.).
The idea is to start a task after Remove action to check whether the item was only removed, or reordered.
private async void observableCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
object removedItem = e.OldItems[0];
var reorderTask = NoticeReorderAsync(removedItem);
try
{
var task = await Task.WhenAny(reorderTask, Task.Delay(100));
if (reorderTask == task)
{
// removedItem was in fact reordered
Debug.WriteLine("reordered");
}
else
{
TryCancelReorder();
// removedItem was really removed
Debug.WriteLine("removedItem");
}
}
catch (TaskCanceledException ex)
{
Debug.WriteLine("removedItem (from exception)");
}
finally
{
tcs = null;
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
object addedItem = e.NewItems[0];
bool added = NoticeAdd(addedItem);
if (added)
{
// addedItem was just added, not reordered
Debug.WriteLine("added");
}
}
}
TaskCompletionSource<object> tcs;
private void TryCancelReorder()
{
if (tcs != null)
{
tcs.TrySetCanceled();
tcs = null;
}
}
private Task NoticeReorderAsync(object removed)
{
TryCancelReorder();
tcs = new TaskCompletionSource<object>(removed);
return tcs.Task;
}
private bool NoticeAdd(object added)
{
if (tcs != null)
{
try
{
if (object.Equals(tcs.Task.AsyncState, added))
{
tcs.TrySetResult(added);
return false;
}
else
{
tcs.TrySetCanceled();
return true;
}
}
finally
{
tcs = null;
}
}
return true;
}

Show back button in charm settings with my privacy page in windows store apps

I have a code which show privacy policy URL in charm settings bar.But what I need is like when user clicks on the privacy policy link it should open another page in charm settings with a back button.How to do the same in the below code
private async void OpenPrivacyPolicy(IUICommand command)
{
Uri uri = new Uri("https://sites.google.com/site/mysite/");
await Windows.System.Launcher.LaunchUriAsync(uri);
}
Finally I figured out the solution,thanks to windows 8.1 Appsetting sample app . First of all add a settingsFlyout XAML page to your project.I added the privacy flyout code in my app's home page like this
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SettingsPane.GetForCurrentView().CommandsRequested += onCommandsRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
SettingsPane.GetForCurrentView().CommandsRequested -= onCommandsRequested;
}
void onCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs e)
{
SettingsCommand defaultsCommand = new SettingsCommand("Privacy", "Privacy",
(handler) =>
{
Privacy sf = new Privacy();
sf.Show();
});
e.Request.ApplicationCommands.Add(defaultsCommand);
}
then in my Privacy.xaml page I added the following code
public Privacy()
{
this.InitializeComponent();
this.Loaded += (sender, e) =>
{
Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += SettingsFlyout1_AcceleratorKeyActivated;
};
this.Unloaded += (sender, e) =>
{
Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated -= SettingsFlyout1_AcceleratorKeyActivated;
};
}
void SettingsFlyout1_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs args)
{
// Only investigate further when Left is pressed
if (args.EventType == CoreAcceleratorKeyEventType.SystemKeyDown &&
args.VirtualKey == VirtualKey.Left)
{
var coreWindow = Window.Current.CoreWindow;
var downState = CoreVirtualKeyStates.Down;
bool menuKey = (coreWindow.GetKeyState(VirtualKey.Menu) & downState) == downState;
bool controlKey = (coreWindow.GetKeyState(VirtualKey.Control) & downState) == downState;
bool shiftKey = (coreWindow.GetKeyState(VirtualKey.Shift) & downState) == downState;
if (menuKey && !controlKey && !shiftKey)
{
args.Handled = true;
this.Hide();
}
}
}
Thanks for all the help everyone! And this code works!If anyone facing difficulty just hit me ;)

How to dynamically bind event to command in WinRT without Reactive framework?

I'm implementing modified version of Behavior for my Windows 8 app according to this guide. It works except one place where the Reactive framework is required:
protected override void OnAttached()
{
var evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
if (evt != null)
{
Observable.FromEventPattern<RoutedEventArgs>(AssociatedObject, Event)
.Subscribe(se => FireCommand());
}
base.OnAttached();
}
The question is simple, how to achieve similar funcitonality without the Reactive frmaework? I've browsed the source of of Rx that can be obtained here, but I'ts just too complicated to me.
I've also succeeded porting to code with the only problem that it work only for fixed type of EventHandler:
protected override void OnAttached()
{
EventInfo evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
if (evt != null)
{
AssignEvent<ItemClickEventHandler>(AssociatedObject, Event, FireCommand);
}
base.OnAttached();
}
protected void AssignEvent<T1>(object instance, string eventName, T1 handler)
{
EventInfo runtimeEvent = instance.GetType().GetRuntimeEvent(eventName);
Func<T1, EventRegistrationToken> add = a => (EventRegistrationToken)runtimeEvent.AddMethod.Invoke(instance, new object[] { a });
Action<EventRegistrationToken> remove = a => runtimeEvent.RemoveMethod.Invoke(runtimeEvent, new object[] { a });
WindowsRuntimeMarshal.AddEventHandler(add, remove, handler);
}
Any idea, how to make it dynamic so I don't have to use specific event handler "ItemClickEventHandler"? Note in classic .NET it' quite simple, but in WinRT I cannot use Delegate.CreateDelegate(...)
Update:
Thanks to Brandon I was able to finish the method, it now looks like this:
protected override void OnAttached()
{
EventInfo evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
if (evt != null)
{
MethodInfo addMethod = evt.AddMethod;
MethodInfo removeMethod = evt.RemoveMethod;
ParameterInfo[] addParameters = addMethod.GetParameters();
Type delegateType = addParameters[0].ParameterType;
Action<object, object> handler = (s, e) => FireCommand(e as RoutedEventArgs);
MethodInfo handlerInvoke = typeof(Action<object, object>).GetRuntimeMethod("Invoke", new[] { typeof(object), typeof(object) });
Delegate #delegate = handlerInvoke.CreateDelegate(delegateType, handler);
Func<object, EventRegistrationToken> add = a => (EventRegistrationToken)addMethod.Invoke(AssociatedObject, new object[] { #delegate });
Action<EventRegistrationToken> remove = t => removeMethod.Invoke(AssociatedObject, new object[] { t });
WindowsRuntimeMarshal.AddEventHandler(add, remove, handler);
}
base.OnAttached();
}
Now I can remove 800kB of Rx dlls, thanks again!
I trolled through the Rx source, and here is the important bit of functionality:
MethodInfo addMethod = eventInfo.GetAddMethod();
MethodInfo removeMethod = eventInfo.GetRemoveMethod();
var addParameters = addMethod.GetParameters();
var delegateType = addParameters[0].ParameterType;
Action<object, object> handler = (object sender, object eventArgs) => FireCommand();
MethodInfo handlerInvoke = typeof(Action<object, object>).GetMethod("Invoke");
Delegate delegate = handlerInvoke.CreateDelegate(delegateType, handler);
Func<EventRegistrationToken> add = a => (EventRegistrationToken)addMethod.Invoke(instance, new object[] { delegate });
Action<EventRegistrationToken> remove = t => removeMethod.Invoke(instance, new object[] { t });
It looks like the important info is they are using MethodInfo.CreateDelegate.