|
You can't. That's the whole point of a Service: it has no interaction at all with the user, and will run even when a user is not logged in. Services run in an isolated session that is absolutely prohibited from any interaction with the user, desktop, display, keyboard, mouse, or any other HMI device.
So it can't start an app that has any interaction with the user because it has no idea what user that might be, or even that there is a keyboard and display attached to the computer ...
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
You can use Task Scheduler to start a Windows App at a given interval if it hasn't already been started (single instance option).
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
My question is in the code comment below:
public class MyBase
{
public string CommonProperty { get; set; }
}
public class ClassOne : MyBase
{
public string ClassOneProperty { get; set; }
}
public class ClassTwo : MyBase
{
public string ClassTwoProperty { get; set; }
}
public class program()
{
var classTwo = new ClassTwo();
classTwo.CommonProperty = "Some string";
classTwo.ClassTwoProperty = "Some other string";
TestFunction(classTwo);
private void TestFunction(object unknownClass)
{
}
}
If you think 'goto' is evil, try writing an Assembly program without JMP.
|
|
|
|
|
You could use the 'as' operator to try and cast it to a known type, if the cast works then you know the object type.
private static void TestFunction(object unknownClass)
{
ClassOne c1 = unknownClass as ClassOne;
if (c1 != null)
{
Console.WriteLine("Object is a ClassOne object");
}
else
{
Console.WriteLine("Object is not a ClassOne object");
}
ClassTwo c2 = unknownClass as ClassTwo;
if (c2 != null)
{
Console.WriteLine("Object is a ClassTwo object");
}
else
{
Console.WriteLine("Object is not a ClassTwo object");
}
}
|
|
|
|
|
Thank you, Tony. I'm trying to avoid duplicating code that accesses the properties common to all the objects passed to TestFunction. If you have a moment, please see my clarification in this thread.
If you think 'goto' is evil, try writing an Assembly program without JMP.
|
|
|
|
|
GetType() will return the object name
static void TestFunction(object unknownClass)
{
string sType = unknownClass.GetType().ToString();
Console.WriteLine(sType);
Console.ReadLine();
}
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
Thank you, Mycroft. I did know about getting the name and type, but that only gets me part way there. I'm trying to avoid duplicating code that accesses the properties common to all the objects passed to TestFunction. If you have a moment, please see my clarification in this thread.
If you think 'goto' is evil, try writing an Assembly program without JMP.
|
|
|
|
|
What I'm trying to do is avoid duplicating code to access/manipulate the common properties. In TestFunction I want to be able to take unknownObject, cast it to its actual class type, and display or change its properties. Something like the following (which won't build):
private void TestFunction(object unknownClass)
{
var localObject = null;
string specificProperty = string.empty;
switch (unknownObject.GetType().Name)
{
case "ClassOne":
localObject = (ClassOne)unknownObject;
specificProperty = object.ClassOneProperty;
break;
case "ClassTwo":
localObject = (ClassTwo)unknownObject;
specificProperty = object.ClassTwoProperty;
break;
}
Console.PrintLine($"Common Property = {localObject.CommonProperty}, Specific Property = {specificProperty}.");
}
If you think 'goto' is evil, try writing an Assembly program without JMP.
|
|
|
|
|
But you are not changing the common property in your example (except it may be because it is an example).
Once you have the type I think there is something like
String s = (unknownobject As ClassOne).CommonProperty
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
Okay, maybe I can work with that. Thanks.
If you think 'goto' is evil, try writing an Assembly program without JMP.
|
|
|
|
|
Which version of C# / Visual Studio are you using?
private void TestFunction(object unknownClass)
{
(MyBase localObject, string specificProperty) = unknownClass switch
{
ClassOne c1 => (c1, c1.ClassOneProperty),
ClassTwo c2 => (c2, c2.ClassTwoProperty),
MyBase b => (b, null),
_ => (null, null),
};
if (localObject is null)
{
Console.WriteLine($"Unknown object: {unknownClass}");
}
else
{
Console.WriteLine($"Common Property = {localObject.CommonProperty}, Specific Property = {specificProperty}.");
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
string s1, s2;
if ( unknownClass is MyBase myBase ) {
s1 = myBase.CommonProperty;
if ( unknownClass is ClassOne one ) {
s2 = one.ClassOneProperty;
} else if ( unknownClass is ClassTwo two ) {
s2 = two.ClassTwoProperty;
}
}
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
How to trigger an event when the last data was read from COM port after a certain time with C#?
Is it possible?
|
|
|
|
|
No really - you only get an Event with new incomming data.
But if you know with which characters your transmission ends you can check this in your Received-Event and you can raise your own (self-created) Event.
|
|
|
|
|
There is no specific way to do that, but if you set up a Timer with a half second interval and a DateTime variable that you compare in it's Tick event against the current time, you can spot it. Then all you need is to set the variable to the current date and time plus your timeout duration each time you process a character from the port.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
It is possible with a timer. I did it in Visual Basic before to send SMS and it was delivered using my phone as gateway, I raised event Sending, see the VB Code and the C# equivalent below-:
'VB
Private Sub ReadPort()
Dim SerialIn As String = Nothing
Dim RXBuffer(SMSPort.ReadBufferSize) As Byte
Dim SMSMessage As String = Nothing
Dim Strpos As Integer = 0
Dim TmpStr As String = Nothing
While SMSPort.IsOpen = True
If (SMSPort.BytesToRead <> 0) And (
SMSPort.IsOpen = True) Then
While SMSPort.BytesToRead <> 0
SMSPort.Read(RXBuffer, 0, SMSPort.ReadBufferSize)
SerialIn =
SerialIn & System.Text.Encoding.ASCII.GetString(
RXBuffer)
If SerialIn.Contains(">") = True Then
_ContSMS = True
End If
If SerialIn.Contains("+CMGS:") = True Then
_Continue = True
RaiseEvent Sending(True)
_Wait = False
SerialIn = String.Empty
ReDim RXBuffer(SMSPort.ReadBufferSize)
End If
End While
RaiseEvent DataReceived(SerialIn)
SerialIn = String.Empty
ReDim RXBuffer(SMSPort.ReadBufferSize)
End If
End While
End Sub
//=======================================================================
//CSharp
private void ReadPort()
{
string SerialIn = null;
byte[] RXBuffer = new byte[SMSPort.ReadBufferSize + 1];
string SMSMessage = null;
int Strpos = 0;
string TmpStr = null;
while (SMSPort.IsOpen == true)
{
if ((SMSPort.BytesToRead != 0) & (SMSPort.IsOpen == true))
{
while (SMSPort.BytesToRead != 0)
{
SMSPort.Read(RXBuffer, 0, SMSPort.ReadBufferSize);
SerialIn = SerialIn + System.Text.Encoding.ASCII.GetString(RXBuffer);
if (SerialIn.Contains(">") == true)
_ContSMS = true;
if (SerialIn.Contains("+CMGS:") == true)
{
_Continue = true;
Sending?.Invoke(true);
_Wait = false;
SerialIn = string.Empty;
RXBuffer = new byte[SMSPort.ReadBufferSize + 1];
}
}
DataReceived?.Invoke(SerialIn);
SerialIn = string.Empty;
RXBuffer = new byte[SMSPort.ReadBufferSize + 1];
}
}
}
You can manipulate the code above and add a timer control for timing.
|
|
|
|
|
I have an app in csharp dot net version 4.7.1 and moving to dotnet version 6.
The snippet of code from 4.7.1 is
Quote: using System.Web; // requires a reference to System.Web.dll
using System.Web.Configuration; // requires a reference to System.Configuration.dll
///
/// Imports an xml store by it's relative path in ASP.NET and returns the requested connection.
/// Does not open the connection.
///
/// <param name="httpContext" />Context of HTTP request to resolve relative path with. (e.g. HttpContext.Current)
/// <param name="configurationFileName" />Full or relative server path. (e.g. ~/App_Data/databases.xml)
/// <param name="connectionName" />Returns a new instance of the provider's class that represents a connection to the database.
public static DbConnection Open(HttpContextBase httpContext, string configurationFileName, string connectionName)
{
DbConnection connection = Connection(httpContext, configurationFileName, connectionName);
connection.Open();
return connection;
}
///
/// Imports an xml store by it's relative path in ASP.NET and returns the requested connection.
/// Does not open the connection.
///
/// <param name="httpContext" />Context of HTTP request to resolve relative path with. (e.g. HttpContext.Current)
/// <param name="configurationFileName" />Full or relative server path. (e.g. ~/App_Data/databases.xml)
/// <param name="connectionName" />Returns a new instance of the provider's class that represents a connection to the database.
/// <returns>Returns a new instance of the provider's class that represents a connection to the database.
public static DbConnection Connection(HttpContextBase httpContext, string configurationFileName, string connectionName)
{
Sources.ImportXmlStore(httpContext.Server.MapPath(configurationFileName));
return Connection(connectionName);
}
I cannot use
using System.Web;
using System.Web.Configuration;
as these don't exist in 6.0 so would appreciate help on how to convert the following to keep the same functionality.
Quote: DbConnection connection = Connection(httpContext, configurationFileName, connectionName);
and
Quote: public static DbConnection Connection(HttpContextBase httpContext, string configurationFileName, string connectionName)
Many thanks for any help.
|
|
|
|
|
DbConnection is in the System.Data.Common namespace; i.e.
using System.Data.Common;
DbConnection Class (System.Data.Common) | Microsoft Docs
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Hi Gerry
Thank you for your reply but that is not the issue. I have that issue is the following is not in 6.0
I have the following at the beginning of my code.
Quote: using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Xml.Linq;
using System.Security.Cryptography;
using System.Web; // requires a reference to System.Web.dll
using System.Web.Configuration; // requires a reference to System.Configuration.dll
I cannot find a reference to items in bold so looking for how to reproduce the same functionality System.Web.Configuration was required for HttpContextBase and WebConfigurationManager
Quote: using System.Web.Configuration; // requires a reference to System.Configuration.dll
HttpContextBase httpContext
ConnectionString = WebConfigurationManager.ConnectionStrings[name].ConnectionString
|
|
|
|
|
|
|
The while loop stop when data reads x, but the buttonTransfer button never gets enabled
and the MessageBox message never shows up, but the program does not either freeze. What can be the problem with this code?
try
{
buttonTransfer.Enabled = false;
port = new SerialPort();
port.BaudRate = 9600;
port.PortName = getValueNew;
port.Open();
port.Write("1");
while (data != "x")
{
data = port.ReadLine();
this.Invoke(new EventHandler(displaydata_event));
}
buttonTransfer.Enabled = true;
MessageBox.Show("Done!");
port.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
|
|
|
|
|
What makes you think that the data you recieve is ever just "x"? Since you are using ReadLine, that call will block until a newline character is entered - the ReadLine will then strip it off, but it is required for your code to work.
I'd start with the debugger, and try following exactly what is happening before I went any further.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I will suggest you put a breakpoint on code line below and step through....
buttonTransfer.Enabled = true;
Your code may not be getting to that point as you assumed. If it gets to that point and your button is a physical object on your form, it must work.
|
|
|
|
|
Three comments:
1.
You should have told us where the code shown is sitting: in some event handler? in a BackGroundWorker's DoWork handler? where?
I can only hope it is not inside a DataReceived handler...
2.
Immediately displaying everything that ReadLine returns would probably be sufficient to find out what goes wrong and when.
3.
A simple "x" will not stop the loop, as ReadLine always waits for a line terminator (actually SerialPort.NewLine, which by default is said to equal Environment.NewLine). Is your peripheral sending "x\n" or "x\n\r" or some such?
Luc Pattyn [My Articles]
The Windows 11 "taskbar" is disgusting. It should be at the left of the screen, with real icons, with text, progress, etc. They downgraded my developer PC to a bloody iPhone.
modified 12-Apr-22 13:15pm.
|
|
|
|