CustomMessageBox from Windows Phone 8 Toolkit throw NullPointerException - c#

Code for creating the CustomMessageBox:
CustomMessageBox is a property, and not a reference to the C# Class in the Toolkit.
CustomMessageBox.Dismissed += (dismissSender, dismissedEvent) =>
{
switch (dismissedEvent.Result)
{
case CustomMessageBoxResult.LeftButton:
PlaceCall(clickedFavorite.Name, clickedFavorite.PhoneNo);
break;
case CustomMessageBoxResult.RightButton:
HERE ---> SendText(clickedFavorite.PhoneNo);
break;
}
};
Code for SendText() method:
private void SendText(String phoneNo)
{
var smsTask = new SmsComposeTask
{
To = phoneNo
};
smsTask.Show();
}
Thing is when the SmsComposeTask has started, the Phone navigates to the SMS application, which is correct.
If the user then decides to go back, with the Hardware Back Button, the SMS application closes and the phone shows my app again - but immediately closes, caused by a NullPointerException:
at Microsoft.Phone.Controls.CustomMessageBox.ClosePopup(Boolean restoreOriginalValues)
at Microsoft.Phone.Controls.CustomMessageBox.<>c__DisplayClass4.<Dismiss>b__1(Object s, EventArgs e)
at Microsoft.Phone.Controls.Transition.OnCompleted(Object sender, EventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
I have also tried to override the OnBackKeyPress event, like this:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (CustomMessageBox != null && CustomMessageBox.IsEnabled)
{
e.Cancel = true;
}
else
{
base.OnBackKeyPress(e);
}
}
Does anyone know what to do?

I have found a solution to my own problem. Instead of using the faulty CustomMessageBox, I found Coding4Fun Windows Phone Toolkit which provides a by far, more stable message box called MessagePrompt - here's how to use it.
Create buttons
var smsButton = new Button { Content = "SMS" };
smsButton.Click += (o, args) =>
{
// do something
};
var buttonList = new List<Button>
{
smsButton
};
Create the actual message prompt
var msgPrompt = new MessagePrompt
{
Title = "Message Prompt Title",
Body = new TextBlock { Text = "Text for the Body", FontSize = 25, TextWrapping = TextWrapping.Wrap },
ActionPopUpButtons = buttonList
};
Show it
msgPrompt.Show()
No bullocks
The good thing, which I have experienced with this MessagePrompt is that you are not bound to two static Left and Right buttons like with CustomMessageBox.
And if you want, you can set the Body property to a whole new XAML page, which makes this control flexible.
Reference: Coding4Fun WP7 Message Prompt in depth

Doesn't this problem has something to do with Windows Phone Application lifecycle. As can be found here, figure 6. When activiting another program when your program is active you should save all application data so when a reactivating event ,such as navigating with your back button back to your application, starts your program again you can load the user's data again.

I'm not sure what's happening, but you can just delay the SMS task to avoid the issue:
CustomMessageBox.Dismissed += (dismissSender, dismissedEvent) =>
{
switch (dismissedEvent.Result)
{
case CustomMessageBoxResult.LeftButton:
PlaceCall(clickedFavorite.Name, clickedFavorite.PhoneNo);
break;
case CustomMessageBoxResult.RightButton:
Dispatcher.BeginInvoke(new Action(() => SendText(clickedFavorite.PhoneNo)));
break;
}
};

My 0.02$: this is a bug in the CustomMessageBox. They're keeping lots of singletons alive there and a good timing bug doesn't do that a world of good. Agreed with KooKiz that you can't work around with that without either fixing CustomMessageBox or waiting until the CustomMessageBox finishes its thing. From my ad-hoc testing it requires anywhere between 2-6 Dispatcher.BeginInvoke() until those actions finish. Instead, maybe consider using DispatcherTimer and wait 256MS which should be enough time.
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var msgBox = new CustomMessageBox()
{
Caption = "foo",
Message = "bar",
LeftButtonContent = "baz",
RightButtonContent = "goo",
IsFullScreen = false,
};
msgBox.Dismissed += (s, args) =>
{
DispatcherTimerHelper.InvokeReallySoon(() =>
{
new SmsComposeTask()
{
Body = "foo",
To = "bar"
}.Show();
});
};
msgBox.Show();
}
public static class DispatcherTimerHelper
{
public static void InvokeReallySoon(Action action)
{
var t = new DispatcherTimer() {Interval = TimeSpan.FromMilliseconds(256)};
t.Tick += (s, args) => action();
t.Start();
}
}

The problem just happen in wp8.
I use the same code in wp7, nothing wrong happens.
Use Code4fun messagebox is a good choice,but is Button Click handler you need to call
MessagePrompt.Hide();
to close the MessagePrompt.

used a boolean on the dismissed event to define which button had been pressed. I then implemented the code I would of implemented in the dismissed event in the Unloaded event instead. This seemed to solve the issue.
i.e
messageBox.Dismissed += (s1, e1) =>
{
switch (e1.Result)
{
case CustomMessageBoxResult.LeftButton:
{
delete = true ;
}
break;
case CustomMessageBoxResult.RightButton:
break;
case CustomMessageBoxResult.None:
break;
default:
break;
}
};
messageBox.Unloaded += (s1, e1) =>
{
if (delete)
DeleteWorkout();
};

This is a known bug.
It was fixed in the latest version.
Remove the reference and install the toolkit again.

Related

CefSharp WPF and Offscreen perfomance

i m trying to suppot an app, that uses cefsharp(v79.1.360).
There are list of things I need to implement:
1) ChromiumWebBrowser in WPF (using CefSharp.Wpf minimum example)
2) This browser can go offscreen(with collapsing window or closing it)
3) Work with JavaScriptObjectRepository, and launch some code, that will be do work with web pages(click buttons, change text of elements). Pages may use frameworks, websockets, Http requests and the other stuff
web pages usually do.
After pages work is done, i send results to C# by calling Methods of object, i bounded in jsObjectRepository/
Expectations:
Offscreen prefomance(time delay) should be as well as With opened window/
Reality:
Offscreen perfomance sometimes is really bad, it take time to do work up to 10 seconds(when wpf is only 1-5).
My code:
Initialization
CefSharpSettings.LegacyJavascriptBindingEnabled = true;
CefSharpSettings.WcfEnabled = true;
CefSettings cefSettings = new CefSettings
{
LocalesDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "locales"),
Locale = appsettings.CurrentChromeLanguage.ToLocal(),
AcceptLanguageList = appsettings.CurrentChromeLanguage.ToAcceptList(),
};
if (!cefSettings.CefCommandLineArgs.ContainsKey("disable-gpu"))
{
cefSettings.CefCommandLineArgs.Add("disable-gpu", "1");
}
if (cefSettings.CefCommandLineArgs.ContainsKey("enable-system-flash"))
{
cefSettings.CefCommandLineArgs.Remove("enable-system-flash");
}
if (cefSettings.CefCommandLineArgs.ContainsKey("enable-media-stream"))
{
cefSettings.CefCommandLineArgs.Remove("enable-media-stream");
}
cefSettings.CefCommandLineArgs.Add("enable-begin-frame-scheduling", "1");
cefSettings.CefCommandLineArgs.Add("disable-gpu-vsync", "1");
cefSettings.CefCommandLineArgs.Add("mute-audio", "true");
cefSettings.CefCommandLineArgs.Add("enable-media-stream", "0");
cefSettings.CefCommandLineArgs.Add("disable-3d-apis", "1");
cefSettings.CefCommandLineArgs.Add("renderer-process-limit", "10");
cefSettings.CefCommandLineArgs.Add("js-flags", "--lite_mode");
if (!appsettings.IsLoadImage)
{
cefSettings.CefCommandLineArgs.Add("disable-image-loading", "1");
}
cefSettings.LogFile = Path.Combine(ClientConfig.ChromeDataPath, "Log.txt");
cefSettings.LogSeverity = LogSeverity.Error;
cefSettings.IgnoreCertificateErrors = true;
cefSettings.SetOffScreenRenderingBestPerformanceArgs();
Browser creating and usage:
ChromiumWebBrowser browser = new ChromiumWebBrowser();
//xaml window with <ContentControl> with browser
//need hide means when window is closing, we cancel it, and using Hide()
NewBrowserView view = new NewBrowserView(new ChromeTabViewModel(browser));
view.Closing += BrowserView_Closing;
Browser.FrameLoadStart += _browser_FrameLoadStart;
var options = new BindingOptions { CamelCaseJavascriptNames = false };
browser.JavascriptObjectRepository.Register("resultController", this, false, options);
//we can just hide window
void BrowserView_Closing(object sender, CancelEventArgs e)
{
if (_needHide)
{
e.Cancel = true;
Hide();
}
}
//on page load
void _browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e) {
string code = "";
code += "(async function(){ " +
"await CefSharp.BindObjectAsync('resultController'); " +
code += TestJsCode;
code += " })();";//AddWorker
e.Frame.ExecuteJavaScriptAsync(code, $"about:blank/myCode");
Consol.WriteLine(DateTime.Now);
}
public void OnGoodResult()
{
Consol.WriteLine(DateTime.Now);
}
public void OnBadResult()
{
Consol.WriteLine(DateTime.Now);
}
//then i just go by differnet pages and await results
As i mentioned before, when i hide wnd, its taking too long time to print result
I really depended on Layouts and other visuals, so i figured this out. I should just set this code, when window is collapsing:
GetBrowser().GetHost().WasHidden(false);

How to listen for "Form.Shown" and "Window.Closing" for a form from a 3rd party DLL?

My C# app calls into a 3rd party DLL. This DLL may or may not show a window (form). I wish to register for a callback / notification / event when this window is shown, and another when the window is closed (by the X or by the "Close" button). Bonus if I can tell the name of the button that caused the action (ie: I'll do something different if they press "Close" or "X", vs. if they press "Purchase")
I do not have access to the source code of this DLL, and the headers don't specify the forms.
Is what I'm needing even possible?
If you're wondering, it's for the PaddleSDK
Use SetWinEventHook
The internet is full of stupid ways to do this but this is the right way. Polling is bad (m' kay?).
If you search StackOverflow for SetWinEventHook and look for the c# hits, you will find lots of examples for use.
Okay wow, this seems to be working: (thanks everyone for the hints!!)
private int[] i_checkoutWindID;
private void RegisterEventListener()
{
Automation.AddAutomationEventHandler(
WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement,
TreeScope.Children,
(sender, e) =>
{
AutomationElement element = sender as AutomationElement;
string automationID = element.Current.AutomationId;
if (automationID != kLicenseWindowAutomationID) return;
i_checkoutWindID = element.GetRuntimeId();
AutomationElement licenseButton = element.FindFirst(
TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, kLicenseButtonAutomationID));
if (licenseButton != null) {
IntPtr hwnd = new IntPtr(licenseButton.Current.NativeWindowHandle);
Control buttonRef = Control.FromHandle(hwnd);
HideButton_Safe(buttonRef);
}
});
Automation.AddAutomationEventHandler(
WindowPattern.WindowClosedEvent,
AutomationElement.RootElement,
TreeScope.Subtree,
(sender, e) =>
{
WindowClosedEventArgs args = e as WindowClosedEventArgs;
if (Automation.Compare(args.GetRuntimeId(), i_checkoutWindID)) {
Array.Clear(i_checkoutWindID, 0, i_checkoutWindID.Length);
<do your "window closed" callback here>;
}
});
}
private void HideButton_Safe(Control buttonRef)
{
if (buttonRef.InvokeRequired) {
var d = new SafeCallDelegate_ButtonHide(HideButton_Safe);
buttonRef.Invoke(d, new object[] { buttonRef });
} else {
buttonRef.Hide();
}
}

Using C# & Xamarin Forms - How can I close one modal without setting of chain of closures

In one stage of my app (Android & iOS are the ones we care about) we've got three pages which take in details and then open a webView for the user to input their card details to take a payment - this can't be done in the app due to Apple's guidelines.
I need to format the navigation in a way that when the user has finished in the webView it closes and then closes the 3 previous modals to get back to the original page. I've got it all working with the Appearing event so each page just closes itself:
this.Appearing += async (s, e) =>
{
await Navigation.PopModalAsync();
};
The issue I'm now having is that when the user presses the back button on the phone, it closes all of the pages that they've been through already & back to the original. I thought about implementing a custom nav bar and disabling the back button on the hardware but this would cause the same problem with the Appearing event.
Is there any easy way to solve this?
EDIT: Relevant code;
async void OnButtonClicked(object sender, EventArgs eventArgs)
{
if (IsConnected)
{
ActivityIndicator.IsVisible = true;
var button = (Button) sender;
button .IsEnabled = false;
await Navigation.PushModalAsync(new Page());
this.Appearing += (s, e) =>
{
ActivityIndicator.IsVisible = false;
button.IsEnabled = true;
RefreshPage();
};
}
else
{
NoInternetLabel.IsVisible = true;
}
}
Use this:
YourButton.Clicked += OpenPage;
OpenPage looks like this:
async public void OpenPage(object sender, EventArgs args)
{
await Navigation.PushAsync(new PageToShow());
}
You don't have to do anything to handle the PageToShow() closing, that happens by itself when the user presses the back button.
Managed to solve this by using Actions. In each new Page() we passed up an async method to close it once the one after had completed;
var nextPage = new Page(async () =>
{
await Navigation.PopModalAsync();
_completedSuccessfully();
});
await Navigation.PushModalAsync(nextPage);
And in the new page class;
private readonly Action _completedSuccessfully;
public Page(Action completedSuccessfully)
{
_completedSuccessfully = completedSuccessfully;
}
This meant that when the webView closed it called the completedSuccessfully() action and then chained all of them to the original page.

How to create informative toast notification in UWP App

In my app, I want to inform user when particular action had performed, like record updated successfully or new record added, but there's not inbuilt control to that can display such information. Is there anything similar to Android Toast.makeText for UWP?
Yes, UWP has Toast Notifications :)
Here is sample code to display simple notification:
private void ShowToastNotification(string title, string stringContent)
{
ToastNotifier ToastNotifier = ToastNotificationManager.CreateToastNotifier();
Windows.Data.Xml.Dom.XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
Windows.Data.Xml.Dom.XmlNodeList toastNodeList = toastXml.GetElementsByTagName("text");
toastNodeList.Item(0).AppendChild(toastXml.CreateTextNode(title));
toastNodeList.Item(1).AppendChild(toastXml.CreateTextNode(stringContent));
Windows.Data.Xml.Dom.IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
Windows.Data.Xml.Dom.XmlElement audio = toastXml.CreateElement("audio");
audio.SetAttribute("src", "ms-winsoundevent:Notification.SMS");
ToastNotification toast = new ToastNotification(toastXml);
toast.ExpirationTime = DateTime.Now.AddSeconds(4);
ToastNotifier.Show(toast);
}
In this article you can find how to customize it:
https://learn.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-adaptive-interactive-toasts
# CSharpToast
Create a toast in c#
This is a Microsoft Visual Studio project that demonstrates showing a toast message to the user.
A toast message is one that appears, then after a delay, disappears without user intervention.
This is needed when either the default language implementation is lacking, see java Android, or when there is no default language implementation.
The steps below illustrate the steps I took to create the toast,
but you can, if desired, just download the app here with all of these steps already completed.
Usage:
Call: Toast.show ("This is a test toast.");
DownloadURL:
git clone https://github.com/pstorli/CSharpToast
Steps To Create:
1) Create a new application in MS Visual Studio.
1.1) File -> New -> Application -> Windows Forms App (.NET Framework)
1.2) Name app as desired, here I used CSharpToast
2) Adjust initial form/screen
2.1) Set Form1.cs name to MainWindow.cs
2.4) Set the StartPosition to CenterScreen
2.5) Add a button1 to the form. Set text to "Make Toast"
2.6) Double click button. A new method should appear:
private void button1_Click(object sender, EventArgs e)
2.7) Add this code to it:
Toast.show ("Toast is done!");
3) Create the toast form.
3.1) In the solution explorer, Add -> New Item -> Windows Form
3.1.1) Set the name to Toast.cs
3.1.2) Set the toast form width and height to toast size, say 6 inches wide by 1/2" tall.
3.1.3) Set the FormBorderStyle to None
3.1.4) Set the background color to white.
3.1.5) Set the start position to CenterScreen
3.2) Add a label to your form
3.2.1) Set the name to Message
3.2.2) Set autosize to false.
3.2.3) Set textalign to MiddleCenter.
3.2.4) Set the background color to white.
3.2.5) Set Dock to fill.
3.3) Add some processing logic to file Toast.cs
3.3.1) Change Toast.cs from this:
using System.Windows.Forms;
namespace CSharpToast
{
public partial class Toast : Form {
public Toast()
{
InitializeComponent();
}
}
}
3.3.2) to this:
3.3.3) Added DEFAULT_MS_DELAY to control how long, by default toast shoould show up.
3.3.4) Added delegate void SafeOnTimedEvent to call Close from differenet thread.
3.3.5) Added constructor with just message and one with message and delay, to override DEFAULT_MS_DELAY
3.3.6) Created toast and added a timer to call, void OnTimedEvent() , when toast is done
which calls Toast.close(); on correct thread.
using System;
using System.Timers;
using System.Windows.Forms;
namespace CSharpToast
{
public partial class Toast : Form {
public static int DEFAULT_MS_DELAY = 2500;
private delegate void SafeOnTimedEvent(Object source, ElapsedEventArgs e);
public Toast (String message)
{
InitializeComponent();
Message.Text = message;
}
public static Toast show (String message)
{
return show(message, DEFAULT_MS_DELAY);
}
public static Toast show (String message, int ms)
{
Toast toast = new Toast(message);
System.Timers.Timer aTimer = new System.Timers.Timer(ms);
aTimer.Elapsed += toast.OnTimedEvent;
aTimer.AutoReset = false;
aTimer.Enabled = true;
toast.ShowDialog();
return toast;
}
private void OnTimedEvent (Object source, ElapsedEventArgs e)
{
if (this.InvokeRequired)
{
var d = new SafeOnTimedEvent(OnTimedEvent);
Invoke(d, new object[] { source, e });
}
else
{
Close();
}
}
}
}
3.4) Run app
3.4.1) The main screen with the "Make Toast" button should appear.
3.4.2) When you press the "Make Toast" button,
3.4.3) a white toast popup should appear that says "Toast is Done!"
3.4.4) which should disappear in 2500 ms.
"I've looked at toast from both sides now, the win and lose and still somehow
it's toast's illusions I recall, I really don't like toast in c# at all."
~Except my CSharpToast version.
Here how to realize simple makeText like android:
private Windows.UI.Xaml.Controls.Frame frame;
private Windows.UI.Xaml.Controls.Page page;
private Ribo.Smart.App.UserControls.Components.Common.Toast toast;
private DispatcherTimer timer = new DispatcherTimer();
void timer_Tick(object sender, object e)
{
if (toast != null)
((Panel)page.FindName("layoutRoot")).Children.Remove(toast);
toast = null;
timer.Stop();
timer.Tick -= timer_Tick;
}
private void Frame_Navigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
if (toast != null)
{
object layoutRoot = page.FindName("layoutRoot");
if (layoutRoot != null)
{
((Panel)layoutRoot).Children.Remove(toast);
page = (Windows.UI.Xaml.Controls.Page)e.Content;
layoutRoot = page.FindName("layoutRoot");
((Panel)layoutRoot).VerticalAlignment = VerticalAlignment.Stretch;
((Panel)layoutRoot).Children.Add(toast);
if (layoutRoot is Grid)
{
toast.SetValue(Grid.RowSpanProperty, 100);
}
}
}
}
public void ShowMessage(string message)
{
frame = (Windows.UI.Xaml.Controls.Frame)Windows.UI.Xaml.Window.Current.Content;
page = (Windows.UI.Xaml.Controls.Page)frame.Content;
frame.Navigated -= Frame_Navigated;
frame.Navigated += Frame_Navigated;
toast = new Ribo.Smart.App.UserControls.Components.Common.Toast();
toast.Message = message;
toast.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Bottom;
toast.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center;
int seconds = message.Length / 30;
if (seconds < 2)
seconds = 2;
timer.Interval = new TimeSpan(0, 0, seconds);
timer.Start();
timer.Tick -= timer_Tick;
timer.Tick += timer_Tick;
object layoutRoot = page.FindName("layoutRoot");
if (layoutRoot != null)
{
if (layoutRoot is Grid)
{
toast.SetValue(Grid.RowSpanProperty, 100);
}
((Panel)layoutRoot).Children.Add(toast);
}
}

Xamarin C# - Android - Prevent an AlertDialog from closing on PositiveButton click

I'm new to Xamarin and I don't know how to do the following in c#. I want to prevent an alertdialog from closing when clicking on the Positive/Negative buttons. I need to do some validation on the input first. If the input is correct, the dialog can close, else I will show a message with instructions. Basically, I have the following code:
private void CreateAddProjectDialog() {
//some code
var alert = new AlertDialog.Builder (this);
alert.SetTitle ("Create new project");
alert.SetView (layoutProperties);
alert.SetCancelable (false);
alert.SetPositiveButton("Create", HandlePositiveButtonClick);
alert.SetNegativeButton("Cancel", HandelNegativeButtonClick);
}
private void HandlePositiveButtonClick (object sender, EventArgs e) {
//Do some validation here and return false (prevent closing of dialog) if invalid, else close....
}
Now, I red the following post on StackOverflow: How to prevent a dialog from closing when a button is clicked
I think the code below (taken from the thread) has the solution, but I don't know how to rewrite my c# code to implement the Java:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
builder.setPositiveButton("Test",
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
//Do nothing here because we override this button later to change the close behaviour.
//However, we still need this because on older versions of Android unless we
//pass a handler the button doesn't get instantiated
}
});
AlertDialog dialog = builder.create();
dialog.show();
//Overriding the handler immediately after show is probably a better approach than OnShowListener as described below
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Boolean wantToCloseDialog = false;
//Do stuff, possibly set wantToCloseDialog to true then...
if(wantToCloseDialog)
dismiss();
//else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
}
});
How to code this in c#? Especially the override part in the setPositiveButton area...
This requires to think a bit outside the box. You will have to manipulate the AlertDialog object directly:
// Build the dialog.
var builder = new AlertDialog.Builder(this);
builder.SetTitle("Click me!");
// Create empty event handlers, we will override them manually instead of letting the builder handling the clicks.
builder.SetPositiveButton("Yes", (EventHandler<DialogClickEventArgs>)null);
builder.SetNegativeButton("No", (EventHandler<DialogClickEventArgs>)null);
var dialog = builder.Create();
// Show the dialog. This is important to do before accessing the buttons.
dialog.Show();
// Get the buttons.
var yesBtn = dialog.GetButton((int)DialogButtonType.Positive);
var noBtn = dialog.GetButton((int)DialogButtonType.Negative);
// Assign our handlers.
yesBtn.Click += (sender, args) =>
{
// Don't dismiss dialog.
Console.WriteLine("I am here to stay!");
};
noBtn.Click += (sender, args) =>
{
// Dismiss dialog.
Console.WriteLine("I will dismiss now!");
dialog.Dismiss();
};

Categories

Resources