I've been struggling with this for a while... I have a programm written using the MVP pattern, I want to have a LogHandler class that must retrieve a string that corresponds to an ID provided in one of these methods, but it also needs to update the GUI, adding items to a listbox. So to simplyfy, imagine this:
if (name != "Peter")
{
Log.RegisterError(31, 4) //errorType, errorID
}
So in the Log class it would then get the string that matches the type and IDs provided and MessageBox it, but what if I want to add that string to a control on the form? I'm using views implemented by the forms to accomplish GUI updating, but since this is a static class I can't...
Also where should errors be checked and raised? Presenter? View? Model?
Thanks in advance
You could add callbacks in you Log class that other object could subscribe to.
Example:
In this example the Presenter can listen for an error code to be logged then receive the error string from the Log from the Model class
public class Logger
{
private static Dictionary<int, List<Action<string>>> _callbacks = new Dictionary<int,List<Action<string>>>();
public static void RegisterLoggerCallback(int errorType, Action<string> callback)
{
// Just using errortype in this exaple, but the key can be anything you want.
if (!_callbacks.ContainsKey(errorType))
{
_callbacks.Add(errorType, new List<Action<string>>());
}
_callbacks[errorType].Add(callback);
}
public static void RegisterLog(int errorType, int errorID)
{
// find error sring with codes
string error = "MyError";
// show messagebox
MessageBox.Show(error);
// tell listeners
if (_callbacks.ContainsKey(errorType))
{
_callbacks[errorType].ForEach(a => a(error));
}
}
}
public class Model
{
public Model()
{
}
public void DoSomething()
{
Logger.RegisterLog(1, 2);
}
}
public class Presenter
{
public Presenter()
{
Logger.RegisterLoggerCallback(1, AddToListbox);
}
private void AddToListbox(string error)
{
// add to listbox when errortype 1 is called somewhere
}
}
This is a very simple example but should give you an idea of a way to achive this.
Related
The project I am currently working on (reduced to this problem) consists of 3 parts:
- A server class
- An interface
- Plugins that implement the interface
Now I want to send a message from a plugin, which is loaded as DLL via Reflection in the server project, to a connected client. Of course I need a function in my server class to send my message. Now the question is how to call this function from my plugin which only knows the interface without the possibility to get the singleton instantiation of the server class.
Theoretically I would say, I set an empty function pointer in the interface, which I then, when loading the plugin, let point to my method, via which I then send the message to the client. The only thing I found are delegates, which cannot be defined in the interface. So what would be an alternative?
Below a pseudocode for illustration. I hope you understand what I would like to do and can get me on the way to a solution. It is important that the plugins don't know any functions about the server, only the SendMessage method.
Pseudocode:
public class Server{
private List<Plugin> mPlugins = new List<Plugin>();
public Server() {
LoadPlugins();
}
public void SendMessage(string message) {
// Here I would send my message to some client
}
private void LoadPlugins() {
// Here I'm loading my plugins (*.dll) from a specific folder into my mPlugins list
// And while I'm looping through my plugins and loading them, I would set the function pointer to SendMessage(); Like:
plugin.SendMyMessage = SendMessage;
}
}
public interface SomeAPI {
string Name {get;set;}
string Version {get;set;}
delegate void SendMyMessage(string message);
}
public class SomePlugin : SomeAPI {
public string Name {get;set;} = "Some plugin";
public string Version {get;set;} = "v1.0.0";
void SendMessage(string message) {
SendMyMessage(message);
}
}
There are many ways to get callbacks from the plugin (if i understand you correctly)
Why not just use and Events, Actions or Funcs
public class ISomething
{
public Action<string,ISomething> MyCallBack { get; set; }
}
public class Server
{
private List<ISomething> mPlugins = new List<ISomething>();
public Server()
{
LoadPlugins();
}
private void LoadPlugins()
{
foreach (var plugin in mPlugins)
plugin.MyCallBack += MyCallBack;
}
private void MyCallBack(string message, ISomething plugin)
{
Console.WriteLine(message);
}
}
I am not sure how to decide about how to refactor some production code. This code works as select records top 1 from db and decided to column containing value under the below.
switch(column_value):
case send_email:
send_email.DoIt();
case enable_somexx:
enable_somexx.DoIt();
case response_email:
response_email.DoIt();
Showing the below examples, there are created classes for every events (records) including a DoIt() method(SendMail, DecideMail, ResponseMail, MailXXX, enable_somexx). The classes include 3 subfolders actions named action, decision, response (actually these classes irrelevant which other because code select top 1 record)
I'm thinking of refactoring this code logic like this:
Create base class named Behaviour
other 3 main classes will inherit from this base class
Code:
public abstract Behaviour
{
public virtual void DoIt(string type) {
}
}
--Also another classes Decision, Response will inherit from Behaviour.
public class Action : Behaviour
{
override void DoIt(string type) {
}
}
public class Email : Action
{
override void DoIt(string type)
{
if(type == SEND)
call_sendmethod
else if(xxx_operation_about_mail)
call_xxx_operation_about_mail
}
}
But I cannot handle (actually I don't like my solution because I don't want to create same class every operations like EmailAction, EmailResponse, EmailDecision or another operations)
If you make this code block refactoring, how would you do it?
Thank you.
Using your idea of refactoring ... this is how I would code it:
Here is an outline:
Create an abstract class for Behavior
Create an action class which inherits Behavior
Then you can code like this to trigger desire "action".
Notice how I override the "Send" behavior to customize it to "special sent".
Here is the fiddle: https://dotnetfiddle.net/m3tjWl
Blockquote
public class Program : Action
{
public static void Main()
{
Console.WriteLine("Hello World");
var command = Console.ReadLine();
//trigger send from Action class
Action x = new Action();
x.DoIt(command);
//trigger send from behavior class
//the lines below are added to show how you can still access the parent behavior, remove or use where appropriate
Behaviour y = x;
y.Send();
}
}
public abstract class Behaviour
{
public virtual void Send()
{
Console.WriteLine("sent");
}
public virtual void EnableX()
{
Console.WriteLine("enabled");
}
public virtual void Reply()
{
Console.WriteLine("replied");
}
public abstract void DoIt(string type);
}
public class Action : Behaviour
{
public override void DoIt(string type)
{
if(type.ToUpper() == "SEND")
this.Send();
else if (type.ToUpper() == "ENABLEX")
this.EnableX();
else if (type.ToUpper() == "REPLY")
this.Reply();
else
Console.WriteLine("Unknown Command");
}
new public void Send()
{
Console.WriteLine("Special Sent");
}
}
here some beginners question after 2 hours of googling.
I have got a WindowsForm named GUI with an listbox item (it not have to be a listbox)
What I want to realize is having a box in the GUI an send from every classes in my project text to that box.
Example:
in Programm.cs I want simply write something like this GUI.WriteToLog("Hello World");
and it should appear in that box.
This GUI.WriteToLog should work in every class.
I tried to write a static function WriteToLog in the GUI class but if its static I cant use the listBox1 in that function.
public partial class GUI : Form
{
public void WriteToLog(string msg)
{
listBox1.Items.Add(msg);
}
}
Here the class that should access the box:
class FileManager
{
internal static void RenameFiles(string filePath)
{
GUI g = new GUI();
g.WriteToLog("Moving Files");
try {
File.Move(filePath, filePath + ".RDY");
}
catch (Exception e)
{
string message = e.ToString();
string caption = "Error";
MessageBox.Show(message, caption);
}
}
EDIT:
More Details what I want to do:
I have to access the ListBox from all of my classes, because it should inform about status. After some more google searches. I figured out that the best way to do this is to write an event ? I this right ? How du I do this ? Example what I want: GUI with the ListBox ... I'm in class "FileManager" Function "RenameFile" there I want write one line to the ListBox "Hey, I'm renaming files now" or I'm in Class "Communicator" in Function "SendEmail" so I want to add a line to the ListBox "Hey dude, I'm sending a fabilous email" ...
When you call the method RenameFiles you create a new instance of the class called GUI. So you're not using the same form.
You can fix your code by using dependency injection when creating your GUI class so that the FileManager has access without needing to create a new class.
By adding something like this to the FileManager and calling the setter on creation of your GUI.
private GUI gui;
public void SetGUI(GUI g)
{
this.gui = g;
}
A solution is use singleton pattern below an example:
public partial class GUI
{
private static GUI _instance;
public static GUI Instance
{
get { return _instance ?? (_instance = new GUI()); }
}
public void WriteToLog(string msg)
{
//[your code]...
}
}
class FileManager
{
internal static void RenameFiles(string filePath)
{
GUI.Instance.WriteToLog("Moving Files");
// [other code]...
}
}
I have the following method
public partial class formTabelasPsi : Form
{
private Form1 Opener { get; set; }
public formTabelasPsi(Form1 opener)
{
this.Opener = opener;
InitializeComponent();
}
public static void publicmethod1(string path)
{
//some code related to path
}
}
I want publicmethod1 to check a checkbox whenever this formTabelasPsi runs it.
I tried to specify it using formTabelasPsi.checkBox1.Checked = true; but the code says a object reference is required.
Maybe this is a newbiez question for most of you, but honestly, as a amateur programmer I didn't find this clearly anywhere.
The checkbox belongs to an instance of that form, you need to reference that instance in order to update it
public void publicmethod1(string path)
{
this.checkBox1.Checked = true;
}
The method also needs to belong to an instance of the form, you can find out more about instances here
I am trying to use a method inside class, from another class.
namespace Crystal.Utilities
{
public class Logging
{
public static void Log()
{
//dostuff
Crystal.MainForm.general_log_add_item("Hello World");
}
}
}
namespace Crystal
{
public partial class MainForm : Form
{
public void general_log_add_item(string msg)
{
listBox1.Items.Add(msg);
}
}
}
I want to be able to call Crystal.Utilities.Logging.Log() from anywhere, and that to be able to call Crystal.MainForm.general_log_add_item() . But It doesn't let me, because if I put it as public, then I can't see it, if it's static then It can't interact with my listbox.
This is a wrong approach. Your class should not call into the UI, as the UI could change. The class should not know nor care about the UI. Instead, the class could expose an event that the form could subscribe to, and update based upon the information contained within the event's arguments.
Here's a hastily thrown together example.
class Program
{
static void Main()
{
Logger.OnLogging += Logger_OnLogging;
Logger.Log();
Logger.OnLogging -= Logger_OnLogging;
}
static void Logger_OnLogging(LoggingEventArgs e)
{
Trace.WriteLine(e.Message);
}
}
public class Logger
{
public delegate void LoggingEventHandler(LoggingEventArgs e);
public static event LoggingEventHandler OnLogging;
public static void Log()
{
// do stuff
RaiseLoggingEvent("Data logged");
}
protected static void RaiseLoggingEvent(string message)
{
if (OnLogging != null)
OnLogging(new LoggingEventArgs(message));
}
}
public class LoggingEventArgs : EventArgs
{
public LoggingEventArgs(string message)
{
this.Message = message;
}
public string Message { get; private set; }
}
Instead of implementing it as a static method, try implementing as a singleton. It's a common trick to make an instance global in scope, and restrict to one instance, without making everything static (and thus unable to be used as an instance).
You have to understand that the window is not static, there is one instance of him, thats why the method cant be static,
you can use
Application.Windows to reach this instance and call the add method.
or you can register the window in his constructor on another class that will mediate the Logging and the window.
If you don't understand tell me and I'll try to be more clear
When you declare a method as "static" you're saying that it's not dependent upon a specific instance of the class it's in.
For example if you have a class named "chair" and you want to count how many chairs there are, you'll do that with a static field, and a static method to return that field's value.
The count of all chairs is not related to a specific chair.
In your case you want to add a static method to add an item to a specific instance of a Form. That's impossible and doesn't make sense.
If you want to add an item to a listBox, it must be through a public method.
So basically what I'm saying is - rethink what you're trying to do, there's a good explanation as to why you're not succeeding in doing that.