Click here to Skip to main content
15,901,373 members
Please Sign up or sign in to vote.
2.50/5 (2 votes)
See more:
I am writing an application under Win CE6.0 using C# in VS2005. My application has multiple forms, so the main form (form1) may open a "Settings" form and this may then open a "Set Time and Date" form. All of these forms need to call a LogEvent() method. I initially achieved this by making the LogEvent() method 'public static' in form1, but this method now needs to call the non-static method serialPort.Write() and I cannot do this from a static method. Can anyone please suggest the best way to deal with this. I have looked at several posts on this subject, but none seem to fit my circumstances.
Posted
Comments
U. G. Leander 18-Jan-16 9:24am    
Why don't you use a Singleton? I think this should do the trick.
F-ES Sitecore 18-Jan-16 9:27am    
You need to pass an instance of the serialPort object to the static method and the function that calls the static method will need to supply the serialPort object. Either than or your static method creates an instance of the serialPort itself. Without seeing the code and knowing what it does it's hard to say.
BillWoodruff 18-Jan-16 11:53am    
"this method now needs to call the non-static method serialPort.Write() and I cannot do this from a static method"

Why not ? Where is the 'serialPort.Write method ... in the Main Form ?
Richard W Allen 18-Jan-16 12:55pm    
Thanks for all the suggestions.

As quick and dirty solution, you could make LogEvent a non static member of form1 and then pass the instance of form1 to the other forms.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 18-Jan-16 11:58am    
Don't you think that this is "quick and dirty solution" solves artificial problem which does not even exist? If some facility is put in the form, it is done by mistake; it should be moved to a proper place, that's it. Please see Solution 3.
—SA
CPallini 18-Jan-16 16:12pm    
'Quick and dirty' is a good description, I suppose.
Sergey Alexandrovich Kryukov 18-Jan-16 16:16pm    
Yes, it's good, I only don't see a point of doing so. Just collecting of development entropy which eventually strikes back.
—SA
I'd suggest to read this: How to declare Global Variable..in C-sharp ?[^]. Sergey Alexandrovich Kryuokov explains ther how to access some objects via using singleton.

Please, read the other answers too.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 18-Jan-16 12:05pm    
My 5, but the root of the problem is that the inquirer started with putting some logging facility (and something else) in one of the form classes. In other words, the problem is purely artificial (making yourself difficulties with sole purpose of having something to overcome bravely :-), so it should be eliminated, not solved — please see Solution 3.
—SA
Maciej Los 18-Jan-16 15:46pm    
Thank you, Sergey.
Don't put your logging facility in any form, it does not belong there. Make your logging function(s) either static or apply the singleton pattern. A good singleton code sample can be found here: C# in Depth: Implementing the Singleton Pattern[^].

—SA
 
Share this answer
 
Comments
Richard W Allen 18-Jan-16 12:13pm    
Agreed. I have now created a singleton for my logging method. Originally I created the serial port in form1 using the SerialPort tool. This gave me the problem that I could not access the non-static serial port from my singleton (or am I missing something?). I have now created a SerialComms class where I instantiated the port and I have a static instance of this class created in form1. Do you think that is the correct implementation?
Sergey Alexandrovich Kryukov 18-Jan-16 12:44pm    
Sounds good. Will you accept the answer formally?

By the way, get rid of auto-generated names such as "form1". They violate (good) Microsoft naming conventions and are not meant to be uses as is. All names should be renamed to some semantically sensible names. For this purpose, you are given the VS refactoring engine.

—SA
Richard W Allen 18-Jan-16 12:54pm    
Many thanks.
Sergey Alexandrovich Kryukov 18-Jan-16 14:39pm    
You are very welcome.
Good luck, call again.
—SA
Maciej Los 18-Jan-16 15:46pm    
5ed!
I think the issue here should be addressed by the architecture of your WinForm solution. I'd try to achieve "separation of concerns" by something like this:

First, I'd have a LogEntry Class:
C#
public class LogEntry
{
    public string Entry { set; get; }
    public DateTime Timestamp { set; get; }

    public LogEntry(string str)
    {
        Entry = str;
        Timestamp = DateTime.Now;
    }
}
I'd use a static Log manager class:
C#
public static class LogManager
{
    public static LogForm TheLogForm { set; get; }

    public static List<logentry> LogEntries { set; get; }

    static LogManager()
    {
        TheLogForm = new LogForm();
        LogEntries = new List<logentry>();
    }

    public static void LogEvent(string str)
    {
        // create a new LogEntry
        LogEntry newEntry = new LogEntry(str);
        
        LogEntries.Add(newEntry);
        // write to serial port if needed ... ?
        // SerialPortManager.Write(str);
    }

    // write methods to display all Log Entrys in LogForm
    public static void DisplayAllLogEntries()
    {
        TheLogForm.Show();
    }

    // write other methods to serialize/de-serialize Log Entries ?
}
How would this work in practice ? Here's a sample Main Form:
C#
#define UseLogging // look up Preprocessor Directives
using System;
using System.IO.Ports;
using System.Windows.Forms;

namespace January_18_WithLogForm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
#if UseLogging
            // set the ThePort
            SerialPortManager.ThePort = new SerialPort("Port1");
#endif
        }

        private void button1_Click(object sender, EventArgs e)
        {
#if UseLogging
                LogManager.LogEvent("button1 click");
#else 
                Console.Writeline("button1 click");
#endif            
        }

        private void button2_Click(object sender, EventArgs e)
        {
#if UseLogging
            LogManager.DisplayAllLogEntries();
#endif
        }
    }
}
Here the Preprocessor Directive #define UseLogging; controls whether code will be executed at run-time.

In the LogForm 'Load Event, I'd write code to access the LogManager.LogEntries, and do the right thing to display it in the LogForm, let the user edit it, save the changes to LogManager.LogEntries, etc.

Finally, I'd have a SerialPort manager class:
C#
using System.IO;
using System.IO.Ports;

public static class SerialPortManager
{
    public static SerialPort ThePort { set; get; }
    
    public static void Write(byte[] buffer, int offset, int count)
    {
        ThePort.Write(buffer, offset, count);
    }

    public static void Write(string str)
    {
        ThePort.Write(str);
    }
}
Why use Properties in the LogManager and LogEntry classes ?: imho, makes serialization "cleaner:" I predict you will want to serialize the Entries, which is very easy to do using WCF.

The key idea here is to separate your concerns out into code modules which you can then ... to some extent ... design/test in isolation before testing how they work together.
 
Share this answer
 
v2
Comments
Richard W Allen 18-Jan-16 14:50pm    
Hi Bill, I am sure your analysis is correct. I am really an embedded micro programmer (originally in assembler) so I am not very comfortable with Windows programming. Thanks for your tutorial I will study it well
BillWoodruff 18-Jan-16 16:54pm    
You're welcome, Richard. I intend to publish a fuller version of this "model" of logging, with many more features, as an article/tutorial here on CodeProject in the next month or so.

Where it gets really fun is when you recursively parse all the Controls on the Form (or Forms), and install single-instances of Event Handlers for Events common to all Controls, like 'Click, 'Leave, 'Enter, and have those single instances call the LogManager to log-them: then when you have turn off logging by using the Preprocessor Directive at run-time, or in code at run-time, you can remove those Event Handlers.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900