I've a Toast notification that execute from outside the project (In a background one). Here you have:
private void SendMessage(string title, string text)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList textElements = toastXml.GetElementsByTagName("text");
textElements[0].AppendChild(toastXml.CreateTextNode(title));
textElements[1].AppendChild(toastXml.CreateTextNode(text));
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
}
My problem is when I try to execute code when the user click the toast, I want to execute part of the code form the Main project. Is there a way to do this?
Thanks
In this article you can find section Handling activation from a toast notification
Shortly:
after toast clicked OnActivated event invoked and you can check arguments.
Using new toast template:
protected override void OnActivated(IActivatedEventArgs e)
{
if (e is ToastNotificationActivatedEventArgs)
{
}
}
and using old template (like I think you have):
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
string launchString = args.Arguments
// ....
}
Related
I have switched to using UWP (Windows.UI.Xaml.Controls) but now have lost the ability to detect when the webview tab text changes.
Example of text
I previously used an OnTitleChanged event but I cannot find an alternative for this in UWP.
I can see the 'DocumentTitle' in the webView, and it is always updating when necessary.
WebView wv_Browser = new WebView();
string Example = wv_Browser.DocumentTitle;
I have tried every built in event in the WebView but not one of them seem to fire when this updates.
Can anyone suggest and alternative way to trigger an event or monitor this value?
Unfortunately, there is no OnTitleChanged event in UWP WebView, but you could inject eval function into html page as Mehrzad Chehraz said. Please refer the following detail code.
Make eval function for detecting title changed.
string functionString = " new MutationObserver(function () { window.external.notify(document.title); }).observe(document.querySelector('title'), { childList: true })";
Call InvokeScriptAsync method to inject eval. (call below when webview navigation completed)
await MyWebView.InvokeScriptAsync("eval", new string[] { functionString });
listen value changed in ScriptNotify event handler
private void MyWebView_ScriptNotify(object sender, NotifyEventArgs e)
{
var title = e.Value;
}
For more info please check UWP WebView tutorial.
What I ended up using
private void CreateWebView()
{
WebView webview = new WebView();
webview .DOMContentLoaded += async (s, e) =>
{
WebView_DOMContentLoaded(webview);
};
webview .ScriptNotify += (s, e) => {
. . . Do whatever
};
}
private async void WebView_DOMContentLoaded(WebView sender)
{
string function = #"new MutationObserver(function(mutations){window.external.notify(document.getElementById('pageTitle').innerHTML)}).observe(document.getElementById('pageTitle'),{attributes:true,childList:true,subtree:true});";
await sender.InvokeScriptAsync("eval", new string[] { function });
}
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);
}
}
Present i am working with SecondaryTile, i want to fire an event when tile is clicked, is there any possibility for that please help me..
Here is my code,
SecondaryTile initialData = new SecondaryTile();
initialData = new SecondaryTile(
ShowID,
ojsShow.Title,
"NoArguments",
new Uri("ms-appx:///Images/" + ojsShow.TileImage),
TileSize.Square150x150);
initialData.VisualElements.ShowNameOnSquare150x150Logo = true;
await initialData.RequestCreateAsync();
In app.xaml you can find whether clicked title or not
protected override void OnActivated(IActivatedEventArgs args)
{
var data= e.TileId;
if(data=="App")
{
//code for normal app start...
}
else
{
//code for tile click..
//you can see the tile in data parameter
}
}
The only thing you can do is to open the app and send some parameters to take action/ handle it..
for the SecondaryTile, I believe you can set the page/ parameters by your new instance ..
for the handling process, you can override the OnActivated event and check the parameters and the page:
protected override void OnActivated(IActivatedEventArgs args)
I am working with NFC using Xamarin Android.
My scenario is to read nfc tag. I have implemented the following, which works using a button. But I would like it so the user doesn't have to press Scan button to scan nfc tag.
OnCreate
scanButton.Click += (object sender, EventArfs e) =>{
var view = (View)sender;
if(view == Resource.Id.scan){
var mesgEl = FindViewById<TextView>(Resource.Id.msg);
msgEl.Text = "Ready to Scan. Touch and hold the tag against the phone.";
InitNfcScanner();
}
}
InitNfcScanner
private void InitialiseNfcScanner(){
// Create an intent filter for when an NFC tag is discovered. When
// the NFC tag is discovered.
var tagDetected = new IntentFilter(NfcAdapter.ActionTagDiscovered);
var filters = new[] { tagDetected };
// When an NFC tag is detected, Android will use the PendingIntent to come back to this activity.
// The OnNewIntent method will invoked by Android.
var intent = new Intent(this, GetType()).AddFlags(ActivityFlags.SingleTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
if (_nfcAdapter == null) {
var alert = new AlertDialog.Builder (this).Create ();
alert.SetMessage ("NFC is not supported on this device.");
alert.SetTitle ("NFC Unavailable");
alert.SetButton ("OK", delegate {
// display message here
});
alert.Show ();
} else {
_nfcAdapter.EnableForegroundDispatch (this, pendingIntent, filters, null);
}
}
OnNewIntent
protected override void OnNewIntent(Intent intent)
{
// onResume gets called after this to handle the intent
Intent = intent;
}
OnResume()
protected override void OnResume ()
{
base.OnResume ();
InitialiseNfcScanner();
if (NfcAdapter.ActionTagDiscovered == Intent.Action) {
// do stuff
}
}
But if i remove the button delegate from OnCreate, and call InitNfcScanner(), I get the error Unable to start activity: java.lang.illegalStateException: Foreground dispatch can only be enabled when your activity is resumed.
I want the user to be able to just scan the asset, once the activity is loaded. What would be a good solution to achieve this?
Can you please add the button delegate in OnCreate and Just call button.PerformClick() in OnResume.
I have now resolved this issue.
The objective was to be able to read nfc tag without pressing Button.
So i removed the button from the view, and I removed the ScanButton delegate from OnCreate.
As I was calling InitialiseNfcScanner inside the OnResume(), this is all i needed, because _nfcAdapter.EnableForegroundDispatch (this, pendingIntent, filters, null);
would create a pendingIntent and looking at the Android Guidelines for this, the ForgroundDispatch can only been called from the OnResume().
See http://developer.android.com/reference/android/nfc/NfcAdapter.html
enableForegroundDispatch
I working on a Windows Phone 7 app with Text-To-Speech capabilities. I'm using Text-To-Speech with Microsoft Translator Service and the following C# code...
// Text-To-Speech with Microsoft Translator Service (http://translatorservice.codeplex.com/)
private void TextToSpeech_Play(object sender, EventArgs e)
{
SpeechSynthesizer speech = new SpeechSynthesizer(CLIENT_ID, CLIENT_SECRET);
//string content = "This is a beautiful day!";
string language = "en";
//speech.SpeakAsync(content, language);
foreach (UIElement element in todayschapter.Children)
{
if (element is TextBlock)
{
string content = (element as TextBlock).Text;
speech.SpeakAsync(content, language);
}
}
}
In this instance, todayschapter is a StackPanel and its Children are TextBlocks. I'm wanting to simply play audio of each TextBlock, in succession. The problem is that it is play the audio of EVERY TextBlock at the same time.
I have a sneaking suspicion that the problem is SpeakAsync(), but I'm not sure. The documentation shows Speak(), but that isn't available (maybe a different version) in the Visual Studio methods helper dropdown (little thing that shows as you type - not sure what it's called).
Is there a way to make it wait for each play to finish before playing the next? Is foreach not the right choice, for this?
As always, if my code just looks stupid, please recommend better ways. I'm very much a beginner programmer.
Just use the Speak instead of the async call, since you want to have it one after another anyway.
The SpeakAsync call is indeed the problem. Unfortunately, since SpeakAsync doesn't return a Task, you can't just convert this to await SpeakAsync() (which would be the most straightforward conversion).
And, looking at the source code, it doesn't fire an event to tell when it's done. So let's add one (in SpeechSynthesizer.cs):
public event EventHandler<SpeechEventArgs> SpeakCompleted;
public void SpeakAsync(string text, string language)
{
this.GetSpeakStreamAsyncHelper(text, language, result =>
{
if (result.Error == null)
{
SoundEffect effect = SoundEffect.FromStream(result.Stream);
FrameworkDispatcher.Update();
effect.Play();
this.OnSpeakCompleted(new SpeechEventArgs(result.Error)); // added to call completion handler
}
else
{
this.OnSpeakFailed(new SpeechEventArgs(result.Error));
}
});
}
// new function
private void OnSpeakCompleted(SpeechEventArgs e)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (SpeakCompleted != null)
SpeakCompleted(this, e);
});
}
Now, you'll need to handle the SpeakCompleted event and start speaking the next string.
Something like this (I haven't even compiled this, so be warned):
private Queue<string> utterances;
private SpeechSynthesizer speech;
private void TextToSpeech_Play(object sender, EventArgs e)
{
speech = new SpeechSynthesizer(CLIENT_ID, CLIENT_SECRET);
speech.SpeechCompleted += new EventHandler<SpeechEventArgs>(TextToSpeech_Completed);
foreach (UIElement element in todayschapter.Children)
{
if (element is TextBlock)
{
string content = (element as TextBlock).Text;
utterances.Enqueue(content);
}
}
TextToSpeech_Completed(null, null); // start speaking the first one
}
private void TextToSpeech_Completed(object sender, SpeechEventArgs e)
{
if (utterances.Any())
{
string contents = utterances.Dequeue();
speech.SpeakAsync(contents);
}
}