In this i am using stopwatch. when stop watch value between 0 to 15 it will play video on screen 1 and after 15 it will display on screen 0 but thread is not starting after Thread.sleep()
public partial class Form2 : Form
{
int[] screentimings = new int[2] { 20, 20 };
Stopwatch sp;
Thread thread1;
//private System.Timers.Timer _timer = new System.Timers.Timer();
public Form2()
{
InitializeComponent();
thread1 = new Thread(new ThreadStart(A));
thread1.SetApartmentState(ApartmentState.STA);
sp = new Stopwatch();
sp.Start();
thread1.Start();
}
[STAThread]
public void showOnMonitor(int showOnMonitor)
{
Screen[] sc;
sc = Screen.AllScreens;
Form1 f = new Form1();
f.FormBorderStyle = FormBorderStyle.None;
f.Left = sc[showOnMonitor].Bounds.Left;
f.Top = sc[showOnMonitor].Bounds.Top;
f.Height=sc[showOnMonitor].Bounds.Height;
f.Width=sc[showOnMonitor].Bounds.Width;
f.StartPosition = FormStartPosition.Manual;
f.ShowDialog();
}
[STAThread]
private void A()
{
long i = sp.Elapsed.Seconds;
if (i > 0 && i < 15)
{
showOnMonitor(1);
}
else
{
showOnMonitor(0);
}
Thread.Sleep(500);
}
}
showOnMonitor(1) code is executed but after 15 seconds showOnMonitor(0) is not working.
I am new with thread don't know whats wrong with it. It might be because of [STAThread] without this it giving Single Thread Exception.
You don't need a thread at all. Threads are used to do more than one action concurrently. Explaining it will be out of scope of this question. Please read more about threads here.
Since you're in .Net 4.5 you can use async/await to accomplish your goal very easily.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
protected async override void OnLoad(EventArgs e)
{
base.OnLoad(e);
await ShowForms();//Show the forms
}
private async Task ShowForms()
{
ShowOnMonitor(1);
await Task.Delay(15000);//15 seconds, adjust it for your needs.
ShowOnMonitor(2);
}
private void ShowOnMonitor(int showOnMonitor)
{
Screen[] allScreens = Screen.AllScreens;
Rectangle screenBounds = allScreens[showOnMonitor - 1].Bounds;
Form1 f = new Form1
{
FormBorderStyle = FormBorderStyle.None,
Left = screenBounds.Left,
Top = screenBounds.Top,
Height = screenBounds.Height,
Width = screenBounds.Width,
StartPosition = FormStartPosition.Manual
};
f.Show();//Use show, not ShowDialog.
}
}
Related
I have some bugs that need fixing, one of them involves an out of memory error.
Does anyone know how to do this properly? Thanks, I don't want it to be too messy, or too complicated. I just want to treat a new image as a buffer to render another image to (because of positional changes), and do it via a background thread. Not the UI thread (Too slow likely).
I get out of memory errors, and such. Also not able to access members of Form1 from within the thread function (images and the like throw access errors such as "Object already in use")
Here is my code:
System.Threading.Thread t;
public Image b;
public Bitmap c;
public Bitmap d;
public Bitmap e;
public Bitmap bg;
public Bitmap spr;
int spritex = 0;
int spritey = 0;
int spritedir = 1;
public Form1()
{
InitializeComponent();
Text = "Escape The Hypno Mansion!!".ToString();
t = new System.Threading.Thread(DoThisAllTheTime);
t.Start();
textBox1.Text = "Press Begin button to start!";
pictureBox1.Image = Image.FromFile(#"Images\introgirl.jpg");
b = new Bitmap(#"Images\introgirl.jpg");
c = new Bitmap(#"Images\sprite.png");
var graphics = Graphics.FromImage(b);
Pen blackpen = new Pen(Color.Black, 3);
graphics.DrawLine(blackpen, 0, 0, 100, 100);
graphics.DrawImage(c, new Point(500, 500));
pictureBox1.Image = b;
//pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
public void DoThisAllTheTime()
{
while (true)
{
Point p = new Point(spritex, spritey);
bg = new Bitmap(#"Images\test.bmp");
spr = new Bitmap(#"Images\sprite.png");
using (var graphics = Graphics.FromImage(bg))
{
graphics.DrawImage(spr, p);
}
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = bg;
pictureBox1.Invalidate();
if (spritedir == 1) { spritex += 5; }
if (spritedir == 2) { spritex -= 5; }
if (spritex < 0) { spritex = 0; spritedir = 1; }
if (spritex > 700) { spritex = 700; spritedir = 2; }
}
}
The reason you can't change the image in your picturebox is because the thread that created the image is not the thread that created the picturebox.
In a debugger you can check this by asking the picturebox for InvokeRequired (function Control.IsInvokeRequired) just before changing the function.
So let's rewrite your function and show that modern classes Like Task are much easier to use the your thread.
I'll start your task when the form is loading, and try to stop it when the form is closing.
private Task myTask = null;
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private void OnFormLoading(object sender, EventArgs e)
{
// Start the task
this.myTask = Task.Run( () => DoMyWork(this.cancellationTokenSource.Token));
}
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
// if the Task is still running, ask it to stop itself:
if (myTask != null && !myTask.IsCompleted)
{ // ask the task to stop and wait until it is completed:
this.cancellationTokenSource.Cancel();
// all Tokens extractes from this source will get state CancellationRequested
// wait maximum 5 seconds until the task is completed:
this.UseWaitCursor = true;
this.myTask.Wait(TimeSpan.FromSeconds(5));
this.UseWaitCursor = false;
// cancel closing if the task is still not completed
e.Cancel = !this.myTask.Completed;
}
}
Now the function DoMyWork:
private void DoMyWork(CancellationToken cancellationToken)
{
// Do the same as in your DoThisAllTheTime
// except that you regularly check cancellationToken.IsCancelRequested:
while(!cancellationToken.IsCancelRequested)
{
// calculate the image to display
var imageToDisplay = ...
this.DisplayImage(imageToDisplay);
}
}
void DisplayImage(Image imageToDisplay)
{
if (this.pictureBox1.InvokeRequired)
{
this.Invoke(new MethodInvoker( () => this.DisplayImage(imageToDisplay)));
}
else
{
this.PictureBox1.Image = imageToDisplay;
}
}
See:
How to cancel a Task and its children
Use InvokeRequired with lambda expression
Dispose every disposable instances before the loop ends. Your memory leak is related with disposable items not being cleaned from memory, so you'll eventually run out of memory in your infinite loop.
At the very least, you'll want to dispose both bitmaps at the end of the loop:
bg = new Bitmap(#"Images\test.bmp");
spr = new Bitmap(#"Images\sprite.png");
I am trying to update the progress bar as per the time taken by a function(which I wrote here in numerical terms) to be processed.But it only shows the last called value.
public static void updateProgress(int x)
{
Program.f.progressBar1.Visible = true;
Program.f.progressBar1.Enabled = true;
Program.f.progressBar1.Value +=x;
Thread.Sleep(5000);
}
above fn is used to update the progress bar.
public static Form1 f;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
f = new Form1();
f.progressBar1.Maximum = 100;
f.progressBar1.Minimum = 0;
f.progressBar1.Value = 0;
updateProgress(25); //fn1
updateProgress(50); //fn2
Application.Run(f);
}
The progressBar directly shows 75% progress.
Thanks
Wrong: you are doing something before form is displayed:
static void Main()
{
f = new Form1(); // form instance is created
f.progressBar1.Maximum = 100;
f.progressBar1.Minimum = 0;
f.progressBar1.Value = 0;
updateProgress(25); // you do something and change property
updateProgress(50); // you do something and change property
Application.Run(f); // here form is displayed and you see the most recent change
}
Correct: to simulate work, which run in background (while form is displayed) you can do something like:
static void Main()
{
f = new Form1(); // form instance is created
f.progressBar1.Maximum = 100;
f.progressBar1.Minimum = 0;
f.progressBar1.Value = 0;
// create and start task running in parallel
Task.Run(() =>
{
Thread.Sleep(3000); // wait long enough until form is displayed
updateProgress(25);
updateProgress(50);
});
Application.Run(f);
}
public static void updateProgress(int x)
{
// Invoke is required because we run it in another thread
f.Invoke((MethodInvoker)(() =>
{
Program.f.progressBar1.Visible = true;
Program.f.progressBar1.Enabled = true;
Program.f.progressBar1.Value +=x;
}));
Thread.Sleep(5000); // simulate work
}
I am working on a c# console program on Windows to move a window, as part of this I am trying to create a transparent box at the target destination to give the user a visual confirmation of the new location. I am currently facing 2 main problems:
I want to place the form in screen coordinates
I want to be able to close the window after the user has confirmed their decision.
Currently I have code in a library that my console client is calling that does this:
public static void CreateBox(Rect rectangle)
{
Form f = new Form();
f.Name = BoxName;
f.BackColor = Color.Blue;
f.FormBorderStyle = FormBorderStyle.None;
f.Bounds = new System.Drawing.Rectangle(rectangle.Left, rectangle.Top, rectangle.Right - rectangle.Left, rectangle.Bottom - rectangle.Top);
f.TopMost = true;
f.Opacity = 0.5;
Application.EnableVisualStyles();
Task.Run(() => Application.Run(f));
}
And after searching some questions on here I have come up with this to attempt to close the form later:
public static void RemoveBox()
{
Form f = Application.OpenForms[BoxName];
if (f != null)
{
f.Close();
}
}
This is throwing an exception as its coming from a different thread, how can I close this window, and how can I place it in screen coordinates exactly where it should go?
EDIT:
I am now using this to attempt to find the box to move/close it unsuccessfully:
public static void CreateBox(Rect rectangle)
{
Form f = new Form();
f.Name = BoxName;
f.BackColor = Color.AliceBlue;
f.FormBorderStyle = FormBorderStyle.None;
f.TopMost = true;
f.Opacity = 0.3;
Application.EnableVisualStyles();
Task.Run(() =>
{
Application.Run(f);
});
MoveBox(rectangle);
}
public static void RemoveBox()
{
IntPtr hWnd = FindBox(new TimeSpan(0, 0, 1));
var proc = Process.GetProcesses().Where(p => p.Handle == hWnd).Single();
if (proc == null)
{
return;
}
proc.Kill();
}
public static void MoveBox(Rect rect)
{
IntPtr hWnd = FindBox(new TimeSpan(0, 0, 1));
MoveWindow(hWnd, rect);
}
private static IntPtr FindBox(TimeSpan timeout)
{
DateTime time = DateTime.Now;
IntPtr hWnd = IntPtr.Zero;
while(DateTime.Now < time.Add(timeout) || hWnd != IntPtr.Zero)
{
hWnd = FindWindowByCaption(IntPtr.Zero, BoxName);
}
return hWnd;
}
Issues with this:
I can't let the FindBox call take long at all because my goal is to make this box appear and snap windows to them as the user drags them and needs to move as they move it around the desktop.
the p.Handle == hWnd check in the RemoveBox function throws and access denied exception.
If you want do just get it working put:
Form.CheckForIllegalCrossThreadCalls = false;
Into your constructor, I do not recommend it however, since it will make the whole Form no longer be thread safe.
EDIT : Here is a quick test I've done using a WinForm. It should run fine on console as well.
public partial class Form1 : Form
{
//Globals
Form f;
Task t;
public Form1()
{
InitializeComponent();
f = new Form();
f.Name = "testForm";
f.BackColor = Color.Blue;
f.FormBorderStyle = FormBorderStyle.None;
f.Bounds = new System.Drawing.Rectangle(0, 0, 100, 100);
f.TopMost = true;
f.Opacity = 0.5;
Application.EnableVisualStyles();
//f.Show();
t = Task.Run(() => Application.Run(f));
}
private void btn_CloseForm_Click(object sender, EventArgs e)
{
if (f.InvokeRequired)
{
this.Invoke(new CloseForm_Delegate(CloseForm));
}
}
delegate void CloseForm_Delegate();
private void CloseForm()
{
f.Close();
}
private void btn_MoveForm_Click(object sender, EventArgs e)
{
if (f.InvokeRequired)
{
//set form position here
this.Invoke(new MoveForm_Delegate(MoveForm), new Point(0, 0));
}
}
delegate void MoveForm_Delegate(Point p);
private void MoveForm(Point p)
{
f.Location = p;
}
}
I have a weird problem (possibly a threading issue) that has been troubling me. I would like to have a progress bar for a task that I run in Excel/VSTO, that is started by clicking a button on the ribbon.
Since all access to the Excel Object model must occur in the main thread, I show my progress form modally on a separate thread. This works great most of the time, but odd things happen when I switch apps or windows via the Windows task bar. For example, if I am in the middle of a run and Excel is maximized, and I click Chrome on my taskbar to give it focus, then I click back to Excel and click between open Excel workbooks in the taskbar previews, sometimes the UI will partially freeze in the progress bar.
In Excel 2007/2010, I can still see the progress bar being updated but I can't drag the toolbar or click the Cancel button; this is why I say the UI partially freezes. Similar stuff happens in Excel 2013/2016 but I haven't tested as much on them.
If Excel has focus and we don't switch to another window during the execution of the task, then the progress bars work perfectly.
Does anyone have an idea what could be going wrong?
Is there another way I can go about displaying the progress bar in Excel to give consistent and reliable behavior? Note the limitation that the actual task needs to run on the main Excel UI thread and that for a progress form to be interactive and display properly, it needs to be on a secondary UI thread. Because of this, solution like using a BackgroundWorker won't work.
class RunSampleProgressTask
{
private ProgressForm _form;
internal volatile bool CancelPending;
internal volatile AutoResetEvent SignalEvent = new AutoResetEvent(false);
internal RunSampleProgressTask()
{
//create a new workbook
Globals.ThisAddIn.Application.Workbooks.Add(Microsoft.Office.Interop.Excel.XlWBATemplate.xlWBATWorksheet);
int hwnd = GetHwnd();
var thread = new Thread(() => ShowProgressForm(hwnd));
thread.SetApartmentState(ApartmentState.STA);
thread.Priority = ThreadPriority.Highest;
thread.Name = "ProgressFormThread";
thread.IsBackground = true;
thread.Start();
SignalEvent.WaitOne();
//In SDI Excel a newly created workbook won't be shown until the function ends so we use a timer to show the new workbook before running Run()
if (IsSDI)
ExecuteTaskIn(200,Run);
else
Run();
}
internal static void ExecuteTaskIn(int milliseconds, Action action)
{
var timer = new System.Windows.Forms.Timer();
timer.Tick += (s, e) =>
{
((System.Windows.Forms.Timer)s).Stop(); //s is the Timer
action();
};
timer.Interval = milliseconds;
timer.Start();
}
//returns true if it is Excel 2013 or 2016 that use the new Single Document Interface
public static bool IsSDI
{
get
{
string appVersion = Globals.ThisAddIn.Application.Version;
return appVersion.StartsWith("15") || appVersion.StartsWith("16");
}
}
private void ShowProgressForm(int hwnd)
{
_form = new ProgressForm(this) {StartPosition = FormStartPosition.CenterScreen};
_form.ShowInTaskbar = false;
_form.FormBorderStyle = FormBorderStyle.FixedSingle;
_form.ShowDialog(new Win32Window(hwnd));
}
protected void ReportProgress(int percent)
{
if (_form == null || !_form.IsHandleCreated) return;
_form.BeginInvoke(new Action(() => _form.SetProgress(percent)));
}
protected void CloseForm()
{
if (_form == null || !_form.IsHandleCreated) return;
_form.BeginInvoke(new Action(() => _form.Close()));
}
internal static int GetHwnd()
{
if (IsSDI)
{
var window = Globals.ThisAddIn.Application.ActiveWindow;
int hwnd = (int)window.GetType().InvokeMember("Hwnd", BindingFlags.GetProperty, null, window, null); //late binding call to get Window.Hwnd
return hwnd;
}
else
{
return Globals.ThisAddIn.Application.Hwnd;
}
}
private const int BufRowSize = 16384; //must be a factor of RowsPerPage
private const int RowsPerPage = 1048576;
private const int BufColSize = 10;
private const int Repetitions = 80;
internal void Run()
{
ReportProgress(0);
Globals.ThisAddIn.Application.ScreenUpdating = false;
Globals.ThisAddIn.Application.EnableEvents = false;
var buf = new string[BufRowSize, BufColSize];
//fill the buffer with sample data
int cnt = 0;
for (int i = 0; i < BufRowSize; i++)
for (int j = 0; j < BufColSize; j++)
buf[i, j] = "String" + (++cnt);
var workbook = Globals.ThisAddIn.Application.ActiveWorkbook;
var sheet = workbook.ActiveSheet;
int currRow = 1;
for (int i = 0; i < Repetitions; i++)
{
if (CancelPending)
{
CloseForm();
Globals.ThisAddIn.Application.ScreenUpdating = true;
Globals.ThisAddIn.Application.EnableEvents = true;
return;
}
sheet.Range[sheet.Cells[currRow, 1], sheet.Cells[currRow + BufRowSize - 1, BufColSize]].Value2 = buf;
currRow += BufRowSize;
if (currRow > RowsPerPage)
{
currRow = 1;
sheet = workbook.Sheets.Add(Missing.Value, sheet);
}
int percent = 100 * (i + 1) / Repetitions;
ReportProgress(percent);
}
CloseForm();
Globals.ThisAddIn.Application.ScreenUpdating = true;
Globals.ThisAddIn.Application.EnableEvents = true;
}
}
public partial class ProgressForm : Form
{
private ProgressBar _progressBar;
private Label _lblStatus;
private Button _btnCancel;
private RunSampleProgressTask _task;
internal ProgressForm(RunSampleProgressTask task)
{
InitializeComponent();
this.Width = 320;
this.Height = 120;
this.ControlBox = false;
_task = task;
_progressBar = new ProgressBar(){Left=10, Top = 10, Width= 300, Height = 30};
_lblStatus = new Label(){Left = 10, Top = 50};
_btnCancel = new Button(){Text = "Cancel", Left = _lblStatus.Right + 10, Top = 50, Width = 100};
_btnCancel.Click += _btnCancel_Click;
this.Controls.Add(_progressBar);
this.Controls.Add(_lblStatus);
this.Controls.Add(_btnCancel);
this.Shown += ProgressForm_Shown;
}
void ProgressForm_Shown(object sender, EventArgs e)
{
_task.SignalEvent.Set();
}
void _btnCancel_Click(object sender, EventArgs e)
{
_task.CancelPending = true;
_lblStatus.Text = "Cancelling...";
}
internal void SetProgress(int percent)
{
_progressBar.Value = percent;
_lblStatus.Text = percent + "%";
}
}
public class Win32Window : IWin32Window
{
public Win32Window(int hwnd)
{
Handle = new IntPtr(hwnd);
}
public Win32Window(IntPtr handle)
{
Handle = handle;
}
public IntPtr Handle { get; private set; }
}
I'm having a problem while trying to switch between a group of photos in a Form(1).
I'm using picturebox.Image in order to view the chosen picture, and after certain time interval (let's say 4Sec) , switch to a random photo in the same group of photos.
While switching between each photo, i would like to show another Form(2) for 1Sec, and then go back to Form(1).
my Code in Form(1):
public partial class Form1: Form
{
public static Timer time;
public static Form mod;
public Form1()
{
InitializeComponent();
time = new Timer();
mod = new Form2();
mod.Owner = this;
mod.Show();
this.Hide();
RunForm1();
}
public void RunForm1()
{
for (int i = 0; i < groupSize; i++)
{
mod.Owner = this;
mod.Show();
this.Hide();
}
}
}
my Code in Form(2):
public partial class Form2: Form
{
public static Timer time;
public int index = -1;
public List<Image> images;
public DirectoryInfo dI;
public FileInfo[] fileInfos;
public Form2()
{
InitializeComponent();
images = new List<Image>();
time = new Timer();
dI = new DirectoryInfo(#"C:\Users\Documents\Pictures");
fileInfos = dI.GetFiles("*.jpg", SearchOption.TopDirectoryOnly);
foreach (FileInfo fi in fileInfos)
images.Add(Image.FromFile(fi.FullName));
index = images.Count;
time.Start();
RunForm2();
}
public void RunForm2()
{
Random rand = new Random();
int randomCluster = rand.Next(0, 1);
while (index != 0)
{
pictureBox1.Image = images[Math.Abs(index * randomCluster)];
setTimer();
index--;
}
}
public void setTimer()
{
if (time.Interval == 4000)
{
this.Owner.Show();
this.Close();
}
}
}
My main problems in this code is:
1. The time is not updating, i mean, time.Interval is always set to 100
2. i dont know why, but, the photos, never shows in the picturebox.Image although, in debug mode it shows that the photos are being selected as properly.
Thank you for you help!
Roy.
You need to use the Tick event from the timer to know when the time has elapsed.
you check if the interval equals (==) 4000, but you need to set it to 4000 (time.Interval = 4000) and then start the timer. Then the Tick event will fire after 4 seconds.
And the problem of the image not being showed could be solved by calling pictureBox1.UpdateLayout();