I have created a small application but I would now like to incorporate some type of logging that can be viewed via listbox. The source of the data can be sent from any number of places. I have created a new logging class that will pass in a delegate. I think Im close to a solution but Im receiving a NullReferenceException and I don’t know the proper solution. Here is an example of what Im trying to do:
Class1 where the inbound streaming data is received.
class myClass
{
OtherClass otherClass = new OtherClass();
otherClass.SendSomeText(myString);
}
Logging Class
class OtherClass
{
public delegate void TextToBox(string s);
TextToBox textToBox;
Public OtherClass()
{
}
public OtherClass(TextToBox ttb)
{
textToBox = ttb;
}
public void SendSomeText(string foo)
{
textToBox(foo);
}
}
The Form
public partial class MainForm : Form
{
OtherClass otherClass;
public MainForm()
{
InitializeComponent();
otherClass = new OtherClass(this.TextToBox);
}
public void TextToBox(string pString)
{
listBox1.Items.Add(pString);
}
}
Whenever I receive data in myClass, its throwing an error. Any help you could give would be appreciated.
Remove the empty constructor and pass the proper delegate in.
class OtherClass
{
public delegate void TextToBox(string s);
private readonly TextToBox textToBox;
public OtherClass(TextToBox textToBox)
{
if (textToBox == null)
throw new ArgumentNullException("textToBox");
this.textToBox = textToBox;
}
public void SendSomeText(string foo)
{
textToBox(foo);
}
}
Change your OtherClass to check for null:
class OtherClass
{
public delegate void TextToBox(string s);
TextToBox textToBox;
Public OtherClass()
{
}
public OtherClass(TextToBox ttb)
{
textToBox = ttb;
}
public void SendSomeText(string foo)
{
var handler = this.TextToBox;
if(handler != null)
{
textToBox(foo);
}
}
}
Now the reason you're getting the exception though is because in your myClass when you're creating a new OtherClass, you're not providing a method the delegate should "point" to. Therefore, when you're OtherClass calls textToBox(foo); there's no method behind it, and it blows up.
In myClass, you're not calling the overloaded OtherClass constructor that takes a TextToBox, so textToBox(foo) fails because textToBox has not been set.
Can you show the code where myClass is initialized and called?
You should pass in myClass constructor you OtherClass instance created in MainForm, don't create OtherClass instance in myClass it's not the instance to which you attached handler.
Related
I made a class which requires the public default constructor but
that is never called; instead another constructor is used at DataGrid.AddingNewItem.
I'd like to tell developers that the default constructor is not for their use.
Is there an attribute which suits the purpose?
I had checked DebuggerNonUserCode and MethodImplAttribute with MethodImplAttributes.InternalCall but not sure that's the proper approach.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.dataGrid1.CanUserAddRows = true;
var list = new List<RowX>();
this.dataGrid1.ItemsSource = CollectionViewSource.GetDefaultView(list);
this.dataGrid1.AddingNewItem += (s, e) => e.NewItem = new RowX("ABC");
}
}
public class RowX
{
public RowX()
{
//this is not used. but CollectionView require this to be public or
//CanUserAddRows doesn't work.
}
public RowX(object o)
{
//this is the actual ctor.
}
public string Text { get; set; }
}
Mark it private
class Foo
{
private Foo() {}
}
You can give your constructor an access modifier.
private This means it can only be called from another constructor in that class.
public class PrivateClass
{
//Only from inside this class:
private PrivateClass()
{
}
public static PrivateClass GetPrivateClass()
{
//This calls the private constructor so you can control exactly what happens
return new PrivateClass();
}
}
internal This means only code in the same assembly (i.e. from inside your library) can access it.
public class InternalClass
{
//Only from within the same assembly
internal InternalClass(string foo)
{
}
}
I just wanted to ask if the following code is a valid method to access the GUI from another class, or if it is bad practice. What I want to do is to write log messages into a RichTextBox in Form1.
If it's bad practice, would it be better to pass a reference of my Form1 to the other class to be able to access the RichTextBox.
I have the following code to access the GUI in my Form1 from another class:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Logger.Init(this.rtbLog);
MyOtherClass myOtherClass = new MyOtherClass();
myOtherClass.DoSomething();
}
}
public class MyOtherClass
{
public void DoSomething()
{
Logger.AppendText("text...");
Logger.AppendText("text...");
Logger.AppendText("text...");
}
}
public static class Logger
{
private static RichTextBox _rtb;
public static void Init(RichTextBox rtb)
{
_rtb = rtb;
}
public static void AppendText(String text)
{
_rtb.AppendText(text);
_rtb.AppendText(Environment.NewLine);
}
}
With Events (thanks to Ondrej):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Logger.EntryWritten += Logger_EntryWritten;
MyOtherClass myOtherClass = new MyOtherClass();
myOtherClass.DoSomething();
}
void Logger_EntryWritten(object sender, LogEntryEventArgs args)
{
rtbLog.AppendText(args.Message);
rtbLog.AppendText(Environment.NewLine);
}
}
public class MyOtherClass
{
public void DoSomething()
{
Logger.AppendText("text...");
Logger.AppendText("text...");
Logger.AppendText("text...");
}
}
public static class Logger
{
public static event EventHandler<LogEntryEventArgs> EntryWritten;
public static void AppendText(string text)
{
var tmp = EntryWritten;
if (tmp != null)
tmp(null, new LogEntryEventArgs(text));
}
}
public class LogEntryEventArgs : EventArgs
{
private readonly String message;
public LogEntryEventArgs(String pMessage)
{
message = pMessage;
}
public String Message
{
get { return message; }
}
}
It's probably fine for a small throw-away project, but otherwise a logger should not know anything about used platform. Then it would be good to use events for example. Raise an event whenever there's a new log entry written and consumers interested in logged entries will subscribe to a delegate.
Also be careful with threads. If you log a message from a different thread than UI you will end up with an exception because you would access a GUI control from a different thread which is forbidden.
EDIT:
Something along these lines. LogEntryEventArgs is a type you have to create and you can give it properties like Message, TimeWritten, Severity, etc.
public static class Logger
{
public static event EventHandler<LogEntryEventArgs> EntryWritten;
public static void AppendText(string text)
{
var tmp = EntryWritten;
if (tmp != null)
tmp(null, new LogEntryEventArgs(text));
}
}
consumer:
Logger.EntryWritten += Logger_OnEntryWritten;
void Logger_OnEntryWritten(object sender, LogEntryEventArgs args)
{
_rtb.AppendText(args.Message);
_rtb.AppendText(Environment.NewLine);
}
Also, don't forget to invoke on a form/dispatch the body of Logger_OnEntryWritten in order to avoid cross-thread access exception (in case you are considering using threads).
I have a Program class which has:
private static ClientBase objClientBase = new ClientBase(new List<RecordType> { RecordType.none }, ModuleType.Monitor);
static void Main(string[] args)
{
objClientBase.Connect(); //IRRELEVANT
objQueueMon = new Main(); //<-INSIDE THIS IS WHERE I WANT TO ACCESS objClientBase
objClientBase.MainModuleThreadManualResetEvent.WaitOne(); //IRRELEVANT
}
This Progam creates a Main class instance as you see:
objQueueMon = new Main();
Notice that they are separated in different files, but the Main class instance is created inside the Program class.
Inside my Program class I want to access that objClientBase.
Do I have to create a constructor method and pass it or make a public access to it?
So what I want to achieve is, inside the Main class, do a objClientBase.FUNCTION
You can do exactly what you just said:
public class Main {
private ClientBase _caller;
public Main (ClientBase caller) {
_caller = caller;
}
}
Or, you can set it later
public class Main {
private ClientBase _caller;
public Main () {
}
// only your assembly sets it
internal SetClientBase(ClientBase cb) {
_caller = cb;
}
// but anyone gets it
// Now you can let some client execute "Function"
public ClientBase Caller {
{return _caller;}
}
}
Just an example
Change the constructor of your Main class to accept a ClientBase object, like this:
public class Main
{
private ClientBase _clientBase;
public Main(ClientBase clientBase)
{
_clientBase = clientBase;
}
public void SomeMethod()
{
// Use ClientBase.FUNCTION here
_clientBase.FUNCTION();
}
}
I have an application with MainWindow and another class called MyClass. MyClass has a method in it that I need to access from the MainWindow class. MyClass is loaded when the application loads. How do I call the method in MyClass from MainWindow without creating a new instance of MyClass:
MyClass class = new MyClass();
?
The straight forward answer to your question is to mark class method as static. That will allow you calling it from any place.
On the other hand, it's probably is not what you really need. Thus, if you create MyClass on application start inside Application class then you need to expose MyClass instance, for example, through application property. Look at the example code.
public class MyClass
{
public void Method()
{
// ...
}
}
The code of your App:
public partial class App
{
public MyClass MyClassInstance { get; private set; }
private void Application_Startup(object sender, StartupEventArgs e)
{
MyClassInstance = new MyClass();
}
}
And the code of window where you call method of your class:
public partial class MainWindow : Window
{
private void Button_Click(object sender, RoutedEventArgs e)
{
((App)Application.Current).MyClassInstance.Method();
}
}
Sounds very suspect, but you do what you are saying by making that method static
public partial class MainWindow
{
public void MethodInMainWindow()
{
// Don't need to create a new instance of MyClass
MyClass.MethodInMyClass();
}
}
public class MyClass
{
public static void MethodInMyClass()
{
// ....
}
}
Here is a little bit of documentation on static vs instance
The code below throws an exception because the abstract constructor is called before the child constructor.
I need to provide an abstract class to capsule some logic from a different part of the program. However i also need to check if the abstract members are initialised correctly rigth after creation without the childclass having any influence over this.
the compiling example below should illustrate my question.
using System;
namespace Stackoverflow
{
class Program
{
static void Main(string[] args)
{
var x = new Thing(5);
var y = new Child(x);
}
}
class Child : AbstractParent
{
Thing childthing;
public Child(Thing provided) : base(){
childthing = provided;
}
public override void Initialise(){
//Exception is thrown here - childthing is still null
parentthing = childthing.Add(1);
}
}
abstract class AbstractParent
{
protected Thing parentthing;
public AbstractParent(){
Initialise();
AssertThingyNotNull();
}
private void AssertThingyNotNull(){
if (parentthing == null) throw new Exception("Waaa");
}
public abstract void Initialise();
}
class Thing
{
private int i;
public Thing(int i){
this.i = i;
}
public Thing Add(int b){
i += b;
return new Thing(i);
}
}
}
Edit #1:
Is there some way to do this by reflecting into the caller (should be the creator of child rigth?) and then reacting on the end of that call?
Edit #2:
Getting the .ctor that creates the child is easy. Manipulating the methods seems something between impossible and a bad idea.
foreach (StackFrame frame in new StackTrace().GetFrames())
{
Console.WriteLine(frame.GetMethod().Name);
}
You can't, basically. This is why you should avoid calling virtual (or abstract) members from a constructor as far as possible - you could end up with code which is running with an incomplete context. Any variable initializers are executed before the base class constructor is called, but none of the code within the constructor body is.
If you need to perform initialization and only want to do that when the derived class constructor is running, then just call Initialise from the derived class constructor to start with.
You can do something similar to what Microsoft did with InitializeComponent()
then let the children call it whenever it can.
Try this.
Edited = cleaner version.
using System;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
var x = new Thing(5);
var y = new Child(x);
}
}
class Child : AbstractParent
{
public Child(Thing provided)
: base()
{
parentthing = provided;
base.Initialise();
}
}
abstract class AbstractParent
{
protected Thing parentthing;
public AbstractParent()
{
}
private void AssertThingyNotNull()
{
if (parentthing == null) throw new Exception("Waaa");
}
public void Initialise()
{
AssertThingyNotNull();
}
}
class Thing
{
private int i;
public Thing(int i)
{
this.i = i;
}
public Thing Add(int b)
{
i += b;
return new Thing(i);
}
}
}