I have wrapper class over Thread:
public class ThreadWrapper
{
private bool Terminated = false;
private string threadName;
private Thread _thread;
public bool needToTerminate
{
get
{
lock (this)
{
return Terminated;
}
}
}
public string ThreadName
{
get
{
lock (this)
{
return threadName;
}
}
}
// for override constructor in derived classes
public ThreadWrapper()
{
}
public ThreadWrapper(string threadName)
{
this.threadName = threadName;
}
public virtual void Run()
{
}
public virtual void Terminate()
{
lock (this)
{
Terminated = true;
}
}
public void Start()
{
lock (this)
{
if (_thread == null)
{
_thread = new Thread(Run);
_thread.Start();
}
}
}
}
Then i create derived class from ThreadWrapper:
public delegate void ProcessMessageDelegate(string message);
public class Reader : ThreadWrapper
{
private ProcessMessageDelegate ProcessMessage;
public Reader(ProcessMessageDelegate processMessage)
: base()
{
this.ProcessMessage = processMessage;
}
public override void Run()
{
// Do something
}
}
Also i have Form with two buttons. The first button for start thread, the second button for "self-terminate" thread.
public partial class MainForm : Form
{
private MyReader Reader;
public MainForm()
{
InitializeComponent();
}
// real method for delegate
private void ProcessMessage(string message)
{
// add line to RichEdit
this.AddSpRRecordLog(message);
}
private void buttonRunTest_Click(object sender, EventArgs e)
{
if (MyReader == null)
{
MessageBox.Show("Wrong!");
return;
}
MyReader.Start();
}
private void buttonStopTest_Click(object sender, EventArgs e)
{
if (MyReader == null)
{
MessageBox.Show("Wrong!");
return;
}
MyReader.Terminate();
}
private void MainForm_Load(object sender, EventArgs e)
{
Reader MyReader = new Reader(new ProcessMessageDelegate(ProcessMessage));
}
If i use this way (create MyReader on FormLoad event) - MyReader does not create. If i create read in buttonRunTest_Click then everything is ok, but in this case i can't terminate MyReader.
This declares a local variable called MyReader that hides the MyReader field:
private void MainForm_Load(object sender, EventArgs e)
{
Reader MyReader = new Reader(new ProcessMessageDelegate(ProcessMessage));
}
Instead, just assign to the field:
private void MainForm_Load(object sender, EventArgs e)
{
MyReader = new Reader(new ProcessMessageDelegate(ProcessMessage));
}
(Incidentally, this isn't a global variable in the conventional sense - if another instance of MainForm is created, it would have its own independent MyReader field)
Related
not very expert of Threading under Windows.
I have a Main WinForm that opens a child form in it's ctor.
public partial class Main : Form
{
public Main()
{
InitializeComponent();
ImgRxUI formStart = new ImgRxUI();
formStart.MdiParent = this;
formStart.WindowState = FormWindowState.Maximized;
formStart.Show();
}
etc..
The ImgRxUI Form (child form) starts a Thread passing to 2 Actions (delegates in simple form).
public partial class ImgRxUI : Form
{
private ImgReceiver oImgReceiver = null;
public ImgRxUI()
{
InitializeComponent();
this.WindowState = FormWindowState.Maximized;
this.ShowIcon = false;
oImgReceiver = new ImgReceiver(UpdateImage, Log);
oImgReceiver.startService();
}
public void UpdateImage(byte[] ProtocolType)
{
...do stuff...
}
public void Log(string Text)
{
this.Invoke((MethodInvoker)delegate
{
LogMethod(Text);
tLog.ScrollToCaret();
});
}
private void LogMethod(string Text)
{
tLog.AppendText(Text + Environment.NewLine);
}
The ImgReceiver as I said starts a thread that listens on a socket...
public class ImgReceiver
{
private Action<byte[]> ImgReceived;
private Action<string> Log;
private System.Threading.Thread Thread_ImgReceiver = null;
public ImgReceiver(Action<byte[]> ImageReceivedDelegate, Action<string> LogDelegate)
{
this.ImgReceived = ImageReceivedDelegate;
this.Log = LogDelegate;
}
public void startService()
{
Thread_ImgReceiver = new System.Threading.Thread(startListening);
Thread_ImgReceiver.IsBackground = true;
Thread_ImgReceiver.Start();
}
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void killService()
{
Thread_ImgReceiver.Abort();
System.Threading.Thread.Sleep(1000);
}
public void startListening()
{ ...do stuff...}
When I close the ImgRxUI form the following event on the form itself gets called
private void ImgRxUI_FormClosing(object sender, FormClosingEventArgs e)
{
oImgReceiver.killService();
}
Hear rises the error in the title.
Wht ?
Thaks
Change the kill Service method to
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void killService(Action action)
{
action.Invoke();
System.Threading.Thread.Sleep(1000);
}
Change the access level Thread_ImgReceiver to public
public System.Threading.Thread Thread_ImgReceiver = null;
and call killService to
private void ImgRxUI_FormClosing(object sender, FormClosingEventArgs e)
{
oImgReceiver.killService(new Action(delegate { oImgReceiver.Thread_ImgReceiver.Abort(); }));
}
Guys i have problem with MVP design pattern becouse am not shure how can i show child view in parent form.
My view does not have MdiParent property. Can i manually create it in view interface?
Very ugly look to every form opens in a new window!
I have two presenters:
MainPresenter (represent mainForm(parent) logic)
TaskPresenter (represent logic for save,insert,delete logic)
Two View interfaces:
IMainView
ITaskView
And two winforms:
MainForm - mainwindow(parrent mdi form)
TaskForm
Check code:
MainPresenter
public class MainPresenter
{
private readonly IMainView view;
private List<ITaskModel> tasks;
// Constructor
public MainPresenter(IMainView view)
{
this.view = view;
this.Init();
this.tasks = new List<ITaskModel>();
}
// Initialize
private void Init()
{
this.view.AddTask += AddTask;
}
// Add task
private void AddTask(object sender, EventArgs e)
{
// Show as MDI CHILD
}
}
IMainView
public interface IMainView
{
event EventHandler<EventArgs> AddTask;
}
TaskPresenter
public class TaskPresenter
{
private readonly ITaskView view;
private List<ITaskModel> tasks;
private bool isNew = true;
private int currentIndex = 0;
// Constructor
public TaskPresenter(ITaskView view)
{
this.view = view;
this.Initialize();
}
// Initialize
public void Initialize()
{
tasks = new List<ITaskModel>();
view.SaveTask += Save;
view.NewTask += New;
view.PrevTask += Previous;
view.NextTask += Next;
}
private void Save(object sender, EventArgs e)
{
}
private void New(object sender, EventArgs e)
{
}
private void Next(object sender, EventArgs e)
{
}
private void Previous(object sender, EventArgs e)
{
}
private void BlankTask()
{
}
private void LoadTask(ITaskModel task)
{
}
}
ITaskView
public interface ITaskView
{
String TaskName { get; set; }
String TaskPriority { get; set; }
DateTime? StartDate { get; set; }
DateTime? DuoDate { get; set; }
event EventHandler<EventArgs> SaveTask;
event EventHandler<EventArgs> NewTask;
event EventHandler<EventArgs> NextTask;
event EventHandler<EventArgs> PrevTask;
}
And here is MainForm
public partial class MainForm : Form, IMainView
{
MainPresenter Presenter;
// Construcor
public MainForm()
{
InitializeComponent();
}
// Events
public event EventHandler<EventArgs> AddTask;
// On load
private void MainForm_Load(object sender, EventArgs e)
{
Presenter = new MainPresenter(this);
}
// On click add task btn
private void addTaskBtn_Click(object sender, EventArgs e)
{
if(AddTask != null)
{
// When is this event triggered i want to show another child form for adding new task
AddTask(this, EventArgs.Empty);
}
}
}
So how can i show TaskView as child in MainView?
UIApplication it is Windows Forms Application but output type Class Library.
Add referance MVPFramework
MainForm
public partial class MainForm : Form , IMainView
{
[Resolve]
public IMainControl mainControl;
public MainForm()
{
InitializeComponent();
}
public bool ShowAsDialog()
{
throw new NotImplementedException();
}
private void openChildFormToolStripMenuItem_Click(object sender, EventArgs e)
{
mainControl.OnOpenChildForm();
}
}
Child Form
public partial class ChildForm : Form , IChildView
{
public ChildForm()
{
InitializeComponent();
}
public bool ShowAsDialog()
{
throw new NotImplementedException();
}
public object MDIparent
{
set
{
this.MdiParent = (Form)value;
}
}
}
CoreApplication it is class Library
IMainControl
public interface IMainControl :IControl
{
void OnOpenChildForm();
}
MainControl
public class MainControl :IMainControl
{
[Resolve]
public IApplicationController applicationController;
public void OnOpenChildForm()
{
IChildControl TransfersOnTheWayControl = applicationController.Resolve<IChildControl>();
TransfersOnTheWayControl.Run();
}
}
IChildControl
public interface IChildControl :IControl
{
void Run();
}
IMainView
public interface IMainView :IView
{
}
IChildView
public interface IChildView :IView
{
bool ShowAsDialog();`enter code here`
object MDIparent { set; }
}
IMainPresenter
public interface IMainPresenter :IPresenter
{
}
IChildPresenter
public interface IChildPresenter :IPresenter
{
bool Ask();
}
MainPresenter
public class MainPresenter :BasePresenter<IMainView>, IMainPresenter
{
}
ChildPresenter
public class ChildPresenter : BasePresenter<IChildView>, IChildPresenter
{
public bool Ask()
{
this.Init();
bool res = View.ShowAsDialog();
ApplicationController.ClearInstance<IChildView>();
return res;
}
public override void Init()
{
View.MDIparent = ApplicationController.GetMainFrom<IMainPresenter>();
base.Init();
}
}
LauncherApplication it is Console Application but output type Windows Form.
class Program
{
static void Main(string[] args)
{
IApplicationController applicationController = new ApplicationController(new ServicesContainerAdapter());
applicationController
//RegisterView
.RegisterView<IMainView, MainForm>()
.RegisterView<IChildView, ChildForm>()
//RegisterPresenter
.RegisterPresenter<IMainPresenter, MainPresenter>()
.RegisterPresenter<IChildPresenter, ChildPresenter>()
//RegisterController
.RegisterController<IMainControl, MainControl>()
.RegisterController<IChildControl, ChildControl>();
IMainPresenter mainPresenter = applicationController.Resolve<IMainPresenter>();
mainPresenter.Init();
Application.Run((Form)mainPresenter.FormObject);
}
}
I have one MainForm (with dataGridView) and DataModule class with my own LoadDataTable method which execute FbCommand select sql and fill datatable in dataset and FbRemoteEvent catch method. When I run my app, in MainForm_OnLoad I call LoadDataTable method and my dataGridView show data successfully. But when my app catch FbRemoteEvent from server and call LoadDataTable method, exception occurred in dataGridView. Why?
MainForm:
public partial class MainForm : Form
{
private readonly DataModule _dataModule = DataModule.GetInstance();
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = _dataModule.AppDataSet;
dataGridView1.DataMember = "MESSAGEQUEUE";
_dataModule.LoadMessageQueueDataTable();
}
}
DataModule:
private void FirebirdRemoteEventOnRemoteEventCounts(object sender, FbRemoteEventEventArgs fbRemoteEventEventArgs)
{
switch (fbRemoteEventEventArgs.Name.Trim().ToUpper())
{
case "QUEUE_NEW_MESSAGE":
if (fbRemoteEventEventArgs.Counts > 0)
{
LoadMessageQueueDataTable();
}
break;
}
}
public void LoadMessageQueueDataTable()
{
if (ConnectToFirebird())
{
using (var firebirdTransaction = FirebirdConnection.BeginTransaction())
{
using (var firebirdCommand = new FbCommand
{
Connection = firebirdTransaction.Connection,
Transaction = firebirdTransaction,
CommandType = CommandType.Text,
CommandText = "select MESSAGEQUEUEID, CREATEDATETIME, SENDER, RECIPIENT, TEXT from MESSAGEQUEUE"
})
{
AppDataSet.Tables["MESSAGEQUEUE"].Clear();
try
{
AppDataSet.Tables["MESSAGEQUEUE"].Load(firebirdCommand.ExecuteReader());
firebirdCommand.Transaction.Commit();
}
catch (FbException firebirdException)
{
firebirdCommand.Transaction.Rollback();
}
}
}
}
}
Error:
In DataModule class add and change FbRemoteEvent handler:
public delegate void DelegateMessageQueueTableUpdate();
public event DelegateMessageQueueTableUpdate MessageQueueTableUpdate;
private void FirebirdRemoteEventOnRemoteEventCounts(object sender, FbRemoteEventEventArgs fbRemoteEventEventArgs)
{
switch (fbRemoteEventEventArgs.Name.Trim().ToUpper())
{
case "QUEUE_NEW_MESSAGE":
if (fbRemoteEventEventArgs.Counts > 0)
{
if (MessageQueueTableUpdate != null)
{
MessageQueueTableUpdate();
}
}
break;
}
}
In MainForm:
public partial class MainForm : Form
{
private readonly DataModule _dataModule = DataModule.GetInstance();
private delegate void RefreshMessageQueueTable();
public MainForm()
{
InitializeComponent();
_dataModule.MessageQueueTableUpdate += () =>
{
if (dataGridView1.InvokeRequired)
{
dataGridView1.Invoke(new RefreshMessageQueueTable(_dataModule.LoadMessageQueueDataTable));
}
else
{
_dataModule.LoadMessageQueueDataTable();
}
};
}
private void MainForm_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = _dataModule.AppDataSet;
dataGridView1.DataMember = "MESSAGEQUEUE";
_dataModule.LoadMessageQueueDataTable();
}
}
I'm trying to add an ListViewItem to a listView on the main form (Form1), from another class(Comm).
Form1:
public ListViewItem lvi_tmp;
private void Form1_Load(object sender, EventArgs e)
{
comm = new Comm(this);
}
public void add_to_reg(ListViewItem tmp)
{
lvi_tmp = tmp;
this.Invoke(new EventHandler(add_to_reg_event));
}
public void add_to_reg_event(Object sender, EventArgs e)
{
lst_reg.Items.Add(lvi_tmp);
lst_reg.Refresh();
this.Refresh();
}
Comm:
public Form1 mainFrm { get; set; }
public Comm (Form1 _form1)
{
mainFrm = _form1;
}
private void Add_item()
{
lvi = new ListViewItem("itemTest");
lvi.SubItems.Add("subitemTest");
lvi.Tag = 1;
mainFrm.add_to_reg(lvi);
}
This code throwing the next Exception:
"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."
Any ideas?
You can check InvokeRequired before callling BeginInvoke(). Perhaps this will work for you:
public void add_to_reg(ListViewItem tmp)
{
lvi_tmp = tmp;
if (this.InvokeRequired))
this.Invoke(new EventHandler(add_to_reg_event));
else
add_to_reg_event(null, null);
}
Although I'd split up add_to_reg_event() and use a lambda to avoid that temporary variable:
public void add_to_reg(ListViewItem tmp)
{
if (this.InvokeRequired))
this.Invoke(new Action(() => add_to_reg_impl(tmp)));
else
add_to_reg_impl(tmp);
}
private void add_to_reg_impl(ListViewItem item)
{
lst_reg.Items.Add(item);
lst_reg.Refresh();
this.Refresh();
}
I want my own Class to start but it seems not to be working.
My Class is:
namespace Ts3_Movearound
{
class TS3_Connector
{
public class ccmove : EventArgs
{
public ccmove(int clid, int cid)
{
this.clid = clid;
this.cid = cid;
}
public int clid;
public int cid;
}
public event EventHandler runningHandle;
public event EventHandler stoppedHandle;
public event EventHandler RequestMove;
bool running = true;
public Main()
{
using (QueryRunner queryRunner = new QueryRunner(new SyncTcpDispatcher("127.0.0.1", 25639))) // host and port
{
this.runningHandle(this, new EventArgs());
while (running == true)
{
this.RequestMove(this, new EventArgs());
System.Threading.Thread.Sleep(1000);
}
this.stoppedHandle(this, new EventArgs());
}
Console.ReadLine();
}
}
}
and i call it this way:
private void button1_Click(object sender, EventArgs e)
{
TS3_Connector conn = new TS3_Connector();
conn.runningHandle += new EventHandler(started);
conn.stoppedHandle += new EventHandler(stopped);
}
but it seems that the Class never starts correctly. The runningEvent never gehts fired, also the stopped and the Request. How can i run this Class now?
The lifespan of your conn object ends when button1_Click has returned. You should declare conn in the class scope.
TS3_Connector conn = null;
private void button1_Click(object sender, EventArgs e)
{
conn = new TS3_Connector();
conn.runningHandle += new EventHandler(started);
conn.stoppedHandle += new EventHandler(stopped);
}
TS3_Connector itself does nothing. You should explicitly call main() (please rename the function to something understandable)