Hello I want to change the position of a form2 created from form1 with a thread in an other thread created in form2 with a struct
Edit:
I made an other post
There is an other problem,
How can I make Form2 stop thinking?
This is a similar code to keep it simple.
When Form1 is loaded a thread is created this thread runs a method with a infinite loop in it and at some time creates Form2 and keeps on looping the problem is that Form2 never stops thinking.
public partial class Form1 : Form
{//Form1
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread childThread = new Thread(new ThreadStart(loop);
childThread.Start();
}
public void loop()
{
int i = 0;
while (true)
{
if (i == 45)
{
Form2 f = new Form2();
f.Show();
}
i = i + 1;
}
}
}
}
public partial class Form2 : Form
{//Form2
public Form2()
{
InitializeComponent();
}
public struct Rect
{
public int Left { get; set; }
public int Top { get; set; }
public int Right { get; set; }
public int Bottom { get; set; }
}
private void Form2_Load(object sender, EventArgs e)
{
Thread childThread = new Thread(new ThreadStart(method));
childThread.Start();
}
public void method()
{
Rect move = new Rect();
move.Left = 100;
move.Top = 100;
this.Invoke(new MethodInvoker(() => { mover(move); }));
}
public void mover(Rect move)
{
this.Left = move.Left;
this.Top = move.Top;
}
}
You should create a method
void SetLeft(int left)
{
this.Left = left;
}
That you can invoke it from any thread:
if (this.InvokeRequired) {
this.Invoke(new MethodInvoker(() => { SetLeft(10); } );
} else {
SetLeft(10);
}
Related
I want to run timer every 10 miliseconds and update GUI label string. I have create Class TimerController, were i can set up System.Threading.Timer properties.
class TimerControl
{
private Timer _timer;
public DateTime StartTime { get; private set; }
public TimeSpan CurrentElapsedTime { get; private set; }
public TimeSpan TotalElapsedTime { get; private set; }
public event EventHandler Tick;
public bool IsTimerRunning { get; private set; }
public string CurrentElapsedTimeString { get; private set; } = "";
public TimerCallback TimerAction { get; private set; }
public object TimerParametr { get; private set; }
public int DueTime { get; private set; }
public int Period { get; private set; }
public TimerControl(TimerCallback timerAction, object state, int dueTime, int period)
{
StartTime = DateTime.Now;
CurrentElapsedTime = TimeSpan.Zero;
TotalElapsedTime = TimeSpan.Zero;
TimerAction = timerAction;
TimerParametr = state;
DueTime = dueTime;
Period = period;
}
public void StartTimer()
{
StartTime = DateTime.Now;
TotalElapsedTime = CurrentElapsedTime;
IsTimerRunning = true;
if (_timer == null)
_timer = new Timer(TimerAction, TimerParametr, DueTime, Period);
else
_timer.Change(DueTime, Period);
}
public void StopTimer()
{
_timer.Change(0, -1);
}
I create TimerControl object in MainForm.cs and I need to create function, that will be triggered by a timer. This function should update GUI time label. But in this function i dont habe access to GUI. How to fix it?
TimerControl timerControl = new TimerControl(StopWatchTimer,null, 0, 10);
public MainForm()
{
InitializeComponent();
}
private void btn_timerStart_Click(object sender, EventArgs e)
{
if(btn_timerStart.Text == "Старт")
{
timerControl.StartTimer();
btn_timerStart.Text = "Стоп";
}
else
{
timerControl.StopTimer();
btn_timerStart.Text = "Старт";
}
}
// Callback timer funnction
private static void StopWatchTimer(object label)
{
//labelTime = // labelTime doesnt exist in current context
}
}
}
I did it like that, everything works fine.
public partial class MainForm : Form
{
TimerControl timerControl;
public MainForm()
{
InitializeComponent();
timerControl = new TimerControl(StopWatchTimer, l_timer, 0, 10);
}
private void btn_timerStart_Click(object sender, EventArgs e)
{
if(btn_timerStart.Text == "Старт")
{
timerControl.StartTimer();
btn_timerStart.Text = "Стоп";
}
else
{
timerControl.StopTimer();
btn_timerStart.Text = "Старт";
}
}
private void StopWatchTimer(object label)
{
Label timeLabel = (Label)label;
TimeSpan elapsed = DateTime.Now - timerControl.StartTime;
this.Invoke(new MethodInvoker(delegate ()
{
timeLabel.Text = elapsed.ToString(#"ss\.ff");
}));
}
}
enter image description here
I have Windows Forms application that connects to Oracle database using a BackgrwoundWorker.
public partial class MainForm : Form, IDataFetcher
{
public EntryForm EntryForm { get; set; }
public ApplicationSettings Settings { get; set; }
private DbDataBackgroundWorker BackgroundWorker { get; set; }
enum QueryStatus { RUNNING, NOT_STARTED }
private QueryStatus;
public BillingForm()
{
InitializeComponent();
// configure background actual opearations
BackgroundWorker = new OpearationBackgroundWorker()
{
OnDataFetch = OnDataFetch,
OnDataFetchCompleted = OnDataFetchCompleted
};
}
public BillingForm(EntryForm parentForm, ApplicationSettings appSettings) : this()
{
EntryForm = parentForm;
Settings = appSettings;
queryStatus = QueryStatus.NOT_STARTED;
}
private void ExecuteButton_Click(object sender, EventArgs e)
{
switch (queryStatus)
{
case QueryStatus.NOT_STARTED:
BackgroundWorker.Start();
break;
case QueryStatus.RUNNING:
BackgroundWorker.Stop();
break;
}
}
public void OnDataFetchCompleted(object sender, RunWorkerCompletedEventArgs e)
{
queryStatus = QueryStatus.NOT_STARTED;
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void OnDataFetch(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
if (worker.CancellationPending)
{
e.Cancel = true;
//MessageBox.Show("Запрос остановлен");
return;
}
// create database handler
var db = new DatabaseConnector(Settings.DbConnectionString);
var model = new BillingModel(db)
{
PostTitle = PostTitle,
StartDate = StartDateTimePicker.Value,
EndDate = EndDateTimePicker.Value,
};
try
{
model.Query((datatable) =>
{
Invoke(new Action(() =>
{
QueryResultDataGridView.DataSource = null;
QueryResultDataGridView.DataSource = datatable;
}));
});
}
catch (Exception exception)
{
Invoke(new Action(() => {
queryStatus = QueryStatus.NOT_STARTED;
}));
}
}
}
When I click on "Start" button (method ExecuteButton_Click) program fetches data in background and put them into a DataGridView.
// this class starts operations in background
public class OpearationBackgroundWorker
{
public Action<object,DoWorkEventArgs> OnDataFetch { get; set; }
public Action<object, RunWorkerCompletedEventArgs> OnDataFetchCompleted { get; set; }
//public Action<object, ProgressChangedEventArgs> OnDataFetchProgress { get; set; }
private BackgroundWorker backgroundWorker = new BackgroundWorker()
{
WorkerSupportsCancellation = true
};
public void Start()
{
backgroundWorker.DoWork += new DoWorkEventHandler(OnDataFetch);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnDataFetchCompleted);
if ( !backgroundWorker.IsBusy )
backgroundWorker.RunWorkerAsync();
else
throw new Exception("Process running!");
}
public void Stop()
{
backgroundWorker.CancelAsync();
backgroundWorker.Dispose();
}
}
public class SimpleModel : AbstractModel
{
public IDatabaseFetcher Db { get; set; }
public string PostTitle { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public BillingModel(IDatabaseFetcher db)
{
Db = db;
}
public override void Query(Action<DataTable> callback)
{
var query = "SELECT * FROM posts WHERE post_titile = " + PostTitle;
Db.Query = query;
Db.Fetch(data => callback(data));
}
}
The program uses C# using construct to automatically handle the database connection.
public interface IDataFetcher
{
void OnDataFetch(object sender, DoWorkEventArgs e);
void OnDataFetchCompleted(object sender, RunWorkerCompletedEventArgs e);
}
class DatabaseConnector : IDatabaseFetcher
{
private string connectionString = "";
public string Query { get; set; }
public DatabaseConnector(string connectionString)
{
this.connectionString = connectionString;
}
// here i query data from db
public void Fetch(Action<DataTable> action)
{
using (var connection = new OracleConnection(connectionString))
using (var cmd = new OracleCommand(Query, connection))
{
connection.Open();
using (var reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
throw new Exception("Empty result!");
}
var dataTable = new DataTable();
dataTable.Load(reader);
// run callback processor
action(dataTable);
}
}
}
}
But now, I want to slightly change the program's behaviour and add the ability manually cancel an operation, and close the connection to the database.
I already know how to cancel the BackgrwoundWorker execution, but I can't find solution for how to manually close connection to database and cancel querying of data running in a background process, when user clicks on the "Stop" button.
How to do this?
i try to refresh a datagridview from a external Timer Class every Time i try this i become the error: thread comprehensive not allowed
Form1.cs:
public void Main_Window_Load(object sender, EventArgs e)
{
SetDatagridView();
}
public void SetDatagridView()
{
DataTable MBServices = new DataTable();
DataView MBServicesVW = new DataView();
MBServices = getMasterServicetblOverview("8");
MBServices.Columns.Add("State", typeof(Image));
MBServices.Columns.Remove("state");
MBServicesVW = new DataView(MBServices);
dataGridSHToverview.DataSource = MBServicesVW;
}
Timer.cs:
class Timer
{
public class NamedTimer : System.Timers.Timer
{
}
public static void TimerDo()
{
Timer timer = new Timer();
timer.Interval = (60000);
timer.Elapsed += Main_Tick;
timer.AutoReset = false;
timer.Start();
}
public static void Main_Tick(object sender, EventArgs args)
{
//there a want to call SetDatagridView()
}
}
timerDo() will be called in the master Class.
thank you for our help
I suggest you to use an event pattern.
Sample Code:
/// TimerManager class
public class TimerManager
{
public void TimerDo()
{
Timer timer = new Timer();
timer.Interval = (60000);
timer.Elapsed += Main_Tick;
timer.AutoReset = false;
timer.Start();
}
public void Main_Tick(object sender, EventArgs args)
{
if (OnTimerManagerTick != null)
OnTimerManagerTick(sender, args);
}
public delegate void TimerTick(object sender, EventArgs args);
public event TimerTick OnTimerManagerTick;
}
///Form1 Class
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
InitDataGridView();
TimerManager timerManager = new TimerManager();
timerManager.OnTimerManagerTick += TimerManager_OnTimerManagerTick;
}
private void TimerManager_OnTimerManagerTick(object sender, EventArgs args)
{
InitDataGridView();
}
private void InitDataGridView()
{
List<PersonTest> personTests = new List<PersonTest>
{
new PersonTest{Name = "Luiz", LastName = "Oliveira", Age = 35},
new PersonTest{Name = "Another", LastName = "Person", Age = 25},
new PersonTest{Name = "Neymar", LastName = "Junior", Age = 28},
};
dgvTestDbClick.DataSource = personTests;
}
}
public class PersonTest
{
public string Name { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
I'm trying to make a list of numericUpDown.value and, when I press the button, it sets a random value from the presenter; but, when I press the button nothing happen, I see the value change but I think it just replace the numeric control with a value instead of set value.
The view :
public partial class Form1 : Form, IForm1
{
public List<decimal> _valueList { get; set; }
public Form1()
{
InitializeComponent();
this._valueList = new List<decimal> { numericUpDown1.Value, numericUpDown2.Value, numericUpDown3.Value, numericUpDown4.Value, numericUpDown5.Value, numericUpDown6.Value };
}
public List<decimal> ValueList
{
get => _valueList; set => _valueList = value;
}
public event EventHandler ButtonClick;
private void button1_Click(object sender, EventArgs e)
{
ButtonClick?.Invoke(sender, e);
}
}
Interface:
public interface IForm1
{
List<decimal> ValueList { get; set; }
event EventHandler ButtonClick;
}
Presenter:
public class PresenterForm1
{
private IForm1 _form1;
public PresenterForm1(IForm1 form1)
{
_form1 = form1;
form1.ButtonClick += ButtonClick;
}
private void ButtonClick(object sender, EventArgs e)
{
var random = new Random();
for(int i = 0; i < 6; i++)
{
_form1.ValueList[i] = random.Next(0, 10);
}
}
If I change the type to List<NumericUpDown> it works, but I think this is the wrong way:
foreach (var item in _form1.ValueList)
{
item.Value = random.Next(0, 99);
}
I have 3 forms: form1(which I want to use my List from form3 in which I create List and Add things to it), form2 ( which contains a button to go back to form1 and a button to go to form3 and get values to the list.
I tried creating the following class:
public class ListArticle
{
public List<string> Clothes { get; private set; }
public List<string> Colors { get; private set; }
public ListArticle()
{
Clothes = new List<string>();
Colors = new List<string>();
}
}
and then declare trying Adding things in the List from form3 like this:
// This is the Declaration
public ListArticle _articles = new ListArticle();
public ListArticle Articles
{
get
{
return _articles;
}
set
{
_articles = value;
}
}
This is how I add:
_articles.Clothes.Add("T-shirt " + tshirt_number.ToString());
_articles.Colors.Add(closestColor2(clist, color));
and this is how I am trying to get the values:
when I close form3
I do this:
Form2 frm = new Form2();
frm.Show();
Articles = _articles;
this.Hide();
in form2 I do nothing..
and in form1 I tried to do it like this:
//declaration
public ListArticle Articles;
public ListArticle _articles
{
get
{
return Articles;
}
set
{
Articles = value;
}
}
//and this is how I tried to do it but it returns null everytime.
private void button3_Click(object sender, EventArgs e)
{
try
{
Form3 f = new Form3();
f.Articles = Articles;
foreach (string c in Articles.Clothes)
{
MessageBox.Show(c);
}
}
catch
{
MessageBox.Show("Articles is null.");
}
}
If you want to be able to share the articles between all forms you could make the Clothes and Colors collection static:
public class ListArticle
{
public static List<string> Clothes { get; private set; }
public static List<string> Colors { get; private set; }
static ListArticle()
{
Clothes = new List<string>();
Colors = new List<string>();
}
}
You can then add articles form one form like this:
ListArticle.Clothes.Add("T-shirt " + tshirt_number.ToString());
ListArticle.Colors.Add(closestColor2(clist, color));
...and retrieve articles from another form like this:
private void button3_Click(object sender, EventArgs e)
{
try
{
foreach (string c in ListArticle.Clothes)
{
MessageBox.Show(c);
}
}
catch
{
MessageBox.Show("Articles is null.");
}
}
Using this approach you don't have to create any additional "article" properties in either of the forms. You just access the same static collections from all forms.