Toast Notifications in Win Forms .NET 4.5 - c#

I've searched through a number of different posts to do with creating toast notifications from a Win Form however when these through I get an error when generating the toast notification.
System.Exception: Element not found. (Exception from
HRESULT:0x80070490).
I have edited the csproj file and added the following:
<PropertyGroup>
<TargetPlatformVersion>10.0.10586</TargetPlatformVersion>
</PropertyGroup>
and added the references to Windows.Data and Windows.UI and also a reference to System.Runtime.dll as per the suggestions in Windows.UI.Notifications is missing
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
using System.Windows.Forms;
using System;
namespace ToastNotify
{
class Notify
{
public void GenerateToast(string header, string content)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastImageAndText02;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode(header));
toastTextElements[1].AppendChild(toastXml.CreateTextNode(content));
XmlNodeList toastImageElements = toastXml.GetElementsByTagName("image");
((XmlElement)toastImageElements[0]).SetAttribute("src", "..\\..\\Resources\\icon.ico");
IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
((XmlElement)toastNode).SetAttribute("duration", "long");
ToastNotification toast = new ToastNotification(toastXml);
try
{
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
Any suggestions as to where I am going wrong?

You should explicitly provide applicationId for CreateToastNotifier.
Like this:
private const String APP_ID = "Microsoft.Samples.DesktopToastsSample";
...
ToastNotificationManager.CreateToastNotifier(APP_ID).Show(toast);
But I have bad news. Starting from Windows 10 1709 WinForms applications just does not show toast notifications. Before that Show(toast) was working, but now it neither throw an exception, nor show any toast notification.
I'm still figuring this out.
As noted by Prateek Shrivastava there are (new) limitations.
Have a look here https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toastnotificationmanager.createtoastnotifier
Update:
Here is the step by step guide, to create a setup with APP_ID so notifications will work on all Windows 10 versions:
Send a local toast notification from desktop C# apps
Update:
It works again in Windows 10 1903 without setup.

Use This and make sure you are setting the Image (Icon) full path if you want to show an icon otherwise just pass null.
public static void GenerateToast(string appid, string imageFullPath, string h1, string h2, string p1)
{
var template = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText04);
var textNodes = template.GetElementsByTagName("text");
textNodes[0].AppendChild(template.CreateTextNode(h1));
textNodes[1].AppendChild(template.CreateTextNode(h2));
textNodes[2].AppendChild(template.CreateTextNode(p1));
if (File.Exists(imageFullPath))
{
XmlNodeList toastImageElements = template.GetElementsByTagName("image");
((XmlElement)toastImageElements[0]).SetAttribute("src", imageFullPath);
}
IXmlNode toastNode = template.SelectSingleNode("/toast");
((XmlElement)toastNode).SetAttribute("duration", "long");
var notifier = ToastNotificationManager.CreateToastNotifier(appid);
var notification = new ToastNotification(template);
notifier.Show(notification);
}

I need to chime in here, because I'm working on a WinForms app (.Net Framework 4.7*) that's failing to build on a GitHub build worker because at some point, support for toast notifications was hacked in with some weird references to these WinMetadata\Windows.*.winmd files.
Woe be to anyone who has found this StackOverflow question.
You're probably targeting the .Net Framework 4.x because you're working on a Win Forms app. .Net Framework 4.8 is supported on Windows 7, and Windows 7 does not have ToastNotifications which is probably the class you're looking for. Hence the problem.
I think the only solution is the one in the updated answer that's most upvoted, which is just target the more modern UWP framework that will only work on Windows 10 and up. But you're still trying to send toast notifications from a framework that's not designed to support it. At some point in your code, you're probably doing a check if the platform you're running on is Windows 10 or newer. Not even a compiler statement, just straight up C# or VB.Net. That's not how the .Net Framework is designed to work - it's meant to be platform-agnostic.
My only advice is; setup a new build target for Windows 10+ and setup your project following the advice from Stephen. That should be the least-hackish way of making WinForms do neat Windows 10 tricks.

Related

Can't connect a midi output device to .net MAUI using DryWetMidi

I am using the library DryWetMIDI for .net 7 and I am trying to connect a MIDI output device to MAUI. When I connect a input device it seems to work fine but the only output from the outputdevice I could get was the following error: Internal error (OUT_SENDSHORTRESULT_INVALIDHANDLE). When I tried everything in a simple console application it works perfectly.
Also because of my lack in experience in Maui I don’t really know if I should change something in the project dependencies or in the builder. Or maybe declare the MIDI in the App or the Appshell...
So I tried to create a input device and a output device and connect them to eachother (This is what the DryWetMIDI suggested). Next I try to get the events from the input and the outup device, the input device works but the output device doesnt.
I use the following code where the ouput device doesnt work in Maui:
private InputDevice inputDevice;
private OutputDevice outputDevice;
private DevicesConnector devicesConnector;
void ConnectMidi()
{
//create input device
inputDevice = InputDevice.GetByName("Keystation Mini 32");
inputDevice.EventReceived += OnEventReceived;
//create ouput device;
outputDevice = OutputDevice.GetByName("Microsoft GS Wavetable Synth");
outputDevice.EventSent += OnEventSent;
//connect them
devicesConnector = inputDevice.Connect(outputDevice);
inputDevice.StartEventsListening();
}
public void OnEventReceived(object sender, MidiEventReceivedEventArgs e)
{
var midiDevice = (MidiDevice)sender;
Debug.WriteLine("This gets called when a key is pressed") ;
}
public void OnEventSent(object sender, MidiEventReceivedEventArgs e)
{
var midiDevice = (MidiDevice)sender;
Debug.WriteLine("This gets never called");
}
If there is anohter solution using a diffrent library or something else I would love to hear it!
Hopefully this makes my problem clear and thanks in advance.
(This is also my first post so feedback would also be nice)
I'm the author of the DryWetMIDI. I've analyzed the problem:
The bug is not with the library, it's a MAUI related one.
The error comes from midiOutOpen system Windows function which fails for Microsoft GS Wavetable Synth in a MAUI project but works for any other project types.
I've reported the bug in MAUI repo: https://github.com/dotnet/maui/issues/12368. So what we have is to wait for response from Microsoft.
Update:
The bug has been moved to WinUI repo: https://github.com/microsoft/microsoft-ui-xaml/issues/8055. Also you can mark your project as Unpackaged and the issue should go away.

How can I compile my code both running in win7 and win10?

I want to use the toast notification of windows 10 API and it is available in windows 10.0.17763.0 or later(https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/send-local-toast?tabs=uwp).
Therefore, I set two TFMs in my project for support windows7 also:
<TargetFrameworks>net6.0-windows7;net6.0-windows10.0.17763.0</TargetFrameworks>
My opinion is to check the OS version. In windows7 it will send the toast notification by a custom control I made. In windows10 it will send the toast notification by origin windows10 API. Here is my code:
var OSVersion = System.Environment.OSVersion;
if (OSVersion.Version.Major == 10 && OSVersion.Version.Build > 17763)
{
new ToastContentBuilder()
.AddArgument("action", "viewConversation")
.AddArgument("conversationId", 9813)
.AddText("Andrew sent you a picture")
.AddText("Check this out, The Enchantments in Washington!")
.Show();
}
else
{
//custom toast...
}
Then I met a situation, the code cannot run in earlier than windows 10.0.17763.0. that Visual Studio reports an error of ToastContentBuilder.Show() below
Finally, I found this tutorial by using the Conditional compilation:
https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/desktop-to-uwp-enhance#support-windows-xp-windows-vista-and-windows-78-install-bases
Then I tried to use the Conditional compilation and modify my code like this:
[System.Diagnostics.Conditional("Win10")]
void ShowNotificationWin10()
{
new ToastContentBuilder()
.AddArgument("action", "viewConversation")
.AddArgument("conversationId", 9813)
.AddText("Andrew sent you a picture")
.AddText("Check this out, The Enchantments in Washington!")
.Show();
}
However, the error is still here. How can I solve this?

Using ToastNotificationManager in .Net5.0

I was using the following code to show a Windows 10 Toast notifications from a .NetCore 3.1 console application, where I was using objects from the following namespaces: Windows.UI.Notifications & Windows.Data.Xml.Dom, in .Net5.0 these namespaces seem to be moved to somewhere else.
public void GenerateToast(string appid, string imageFullPath, string h1, string h2, string p1)
{
try
{
var template = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText04);
var textNodes = template.GetElementsByTagName("text");
textNodes[0].AppendChild(template.CreateTextNode(h1));
textNodes[1].AppendChild(template.CreateTextNode(h2));
textNodes[2].AppendChild(template.CreateTextNode(p1));
if (File.Exists(imageFullPath))
{
XmlNodeList toastImageElements = template.GetElementsByTagName("image");
((XmlElement)toastImageElements[0]).SetAttribute("src", imageFullPath);
}
IXmlNode toastNode = template.SelectSingleNode("/toast");
((XmlElement)toastNode).SetAttribute("duration", "long");
var notifier = ToastNotificationManager.CreateToastNotifier(appid);
var notification = new ToastNotification(template);
notifier.Show(notification);
}
catch (Exception)
{
// Ignore
}
}
How to get back these namespaces?
Solution found Here:
This option is only supported in projects that use .NET 5 (or a later release) and target Windows 10, version 1809 or a later OS release. For more background info about this scenario, see this blog post.
With your project open in Visual Studio, right-click your project in
Solution Explorer and choose Edit Project File. Your project file
should look similar to this.
WinExe
net5.0
true
Replace the value of the TargetFramework element with one of the
following strings:
net5.0-windows10.0.17763.0: Use this value if your app targets
Windows 10, version 1809. net5.0-windows10.0.18362.0: Use this value
if your app targets Windows 10, version 1903.
net5.0-windows10.0.19041.0: Use this value if your app targets
Windows 10, version 2004.
For example, the following element is for a project that targets
Windows 10, version 2004.
net5.0-windows10.0.19041.0
Save your changes and close the project file.

Showing a Windows 10 toast notification

I'm developing a program in C# (Visual Studio 2015) and I want to show a toast message to the user at a certain situation. I downloaded this code from the MSDN and it runs fine:
// Get a toast XML template
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText04);
// Fill in the text elements
XmlNodeList stringElements = toastXml.GetElementsByTagName("text");
for (int i = 0; i < stringElements.Length; i++)
{
stringElements[i].AppendChild(toastXml.CreateTextNode("Line " + i));
}
// Specify the absolute path to an image
String imagePath = "file:///" + Path.GetFullPath("toastImageAndText.png");
XmlNodeList imageElements = toastXml.GetElementsByTagName("image");
imageElements[0].Attributes.GetNamedItem("src").NodeValue = imagePath;
// Create the toast and attach event listeners
ToastNotification toast = new ToastNotification(toastXml);
toast.Activated += ToastActivated;
toast.Dismissed += ToastDismissed;
toast.Failed += ToastFailed;
// Show the toast. Be sure to specify the AppUserModelId on your application's shortcut!
ToastNotificationManager.CreateToastNotifier(APP_ID).Show(toast);
After testing this code I wanted to implement it into my application. So I changed it up a little bit and tried to run it. The error messages:
The type "IReadOnlyList<>" is defined in a not referenced assembly. Add a reference to System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
(translated)
Same goes for IEnumerable<> and IReadOnlyList<>
The error come from these two lines:
for (int i = 0; i < stringElements.Length; i++)
{
stringElements[i].AppendChild(toastXml.CreateTextNode("Line " + i));
I also tried adding the reference to System.Runtime. I downloaded it with NuGet (https://www.nuget.org/packages/System.Runtime/4.0.0/).
After that the errors were gone, but now literaly every word in my code is cringled red with error like "System.Object is not defined" and so on (but it still runs when I start it!).
The only possible solution I can think of is that System.Runtime is already installed somewhere on my computer, and that 4.0.0 is the wrong version for my program. But I can't find it anywhere.
PS: It's a desktop-application, not a Windows-Store application.
I think it is the same problem as in this question
You must add a reference to
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\Facades\System.Runtime.dll
PS : If you have a Windows 10 only desktop app, you might want to use the new toast system, the code sample on MSDN uses the Windows 8 one. it works on W10 but does not have all the new features (Microsoft released an official NuGet package).
Edit : Since I can't comment, I will post the answer here :
The exception is because you need to provide an applicationId in CreateToastNotifier()
ToastNotificationManager.CreateToastNotifier("MyApplicationId").Show(toast);
It is the name that will be used in the action center to group your toasts (so in general, you put the name of your app). In Windows 8.1 it was needed to register your application Id (I think this was in the sample from the MSDN) but now you can just put the name of your app.
And the GetXml() is only for WinRT. In desktop you need to do like you did with the GetContent().

Recommended way to test for iOS Version specific feature at runtime

I'm targetting IOS 4.3 and 5.0 with an app built against the 5.0 SDK and would like to add support for the Twitter functionality introduced in iOS5 only when the app runs on a iOS5 device. What is the recommended way to reliably test for the availability of these OS features at runtime without having your app crash?
I know you do this using respondsToSelector in Objective-C but how is it done in C#?
With recent MonoTouch versions you can use the following code:
if (UIDevice.CurrentDevice.CheckSystemVersion (5, 0)) {
window.RootViewController = navigation;
} else {
window.AddSubview (navigation.View);
}
Otherwise you can get a string from UIDevice.CurrentDevice.SystemVersion and do some checks with your own code.
Follow up to comments, including mine...
If you want to check by feature you can do something like:
MonoTouch.Twitter.TWRequest req = new MonoTouch.Twitter.TWRequest ();
if (req.Handle == IntPtr.Zero) {
Console.WriteLine ("No Twitter support before iOS5");
}
What happens is that the selector to create the TWRequest instance will return null and the .NET object will be created in an invalid (unusable) state that you can query with the Handle property. Again YMMV, testing is key :-)

Categories

Resources