I write program for sorting music.
For saving your time and better understanding of my issue,i will write short.
Here is my problem.
I have some cycle in MainMethod.
Here is cycle
private void OkButton(object sender, RoutedEventArgs e)//when i press ok button in Main window i run cycle
{
for (int i = 0; i < 50; i++)
{
//do something.
Window window1 = new Window();
window1.ShowDialog();//if i use ShowDialog it blocks MainWindow.
//window1.Show();if i use Show it continues creating new windows. in cycle.
}
}
So i need to delay executing MainWindow OkButton method,while window1 is opened.Without blocking Main Window.
You can use async/await and a semaphore along these lines:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var signal = new SemaphoreSlim(0, 1);
for (int i = 0; i < 10; i++)
{
var window = new Window();
window.Closed += (s, _) => signal.Release();
window.Show();
await signal.WaitAsync();
}
}
Related
i have a WPF application with main window and second window that opened from main window button. i want the main window opacity to change while second window is open and when i will close it the opacity of the main window will back to defaut.
This is your first window's code to invoke the second window.
var newWindow = new Window1();
newWindow.ShowDialog();
You can add an event handler to newWindow to detect Window1's close.
var newWindow = new Window1();
Application.Current.MainWindow.Opacity = 0.5;
newWindow.Closed += (sender, e) =>
{
Application.Current.MainWindow.Opacity = 1;
};
newWindow.ShowDialog();
got it....
private void Window_Closed(object sender, EventArgs e)
{
Application.Current.MainWindow.Opacity = 1;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.Opacity = 1;
}
I've got the following problem:
I have a Loadscreen and the MainWindow. Everytime I run the application, the Loadscreen comes first, closes after some seconds and than the MainWindow opens. My problem is, that the Mutex is not checking, if the application is already running anymore. Do you know my fallacy?
App.xaml:
public void Application_Startup(object sender, StartupEventArgs e)
{
bool Absicherung;
Mutex Mutex = new Mutex(true, this.GetType().GUID.ToString(), out Absicherung);
if (Absicherung)
{
Window W = new Loadscreen();
W.Closed += (sender2, args) => Mutex.Close(); ;
W.Show();
}
else // ...
Any my Loadscreen.xaml.cs:
public void Timer_Tick(object sender, EventArgs e)
{
progressBar_Ladebalken.Value = i;
label_Titel.Content = i + "%";
if (i < 100)
{
i += 1;
}
else
{
i = 0;
Timer.Stop();
Window W = new MainWindow();
W.Show();
this.Close();
}
}
Please not: It worked before I changed "Window W = new MainWindow();" to "Window W = new Loadscreen();" --> but I want the Loadscreen to come first. In this (first) case, the Loadscreen is ignored.
The problem here is that you are closing the Mutex as soon as your LoadScreen is closed.
Before you changed the code from MainWindow to LoadScreen, it worked fine. Now, what happens is that the Mutex is closed when the LoadScreen is closed, and once the MainWindow opens after the Timer elapses, there is no Mutex, and another instance of the app can be opened.
To fix it, you need to move the Mutex.Close() logic to the Close event of the MainWindow:
public void Application_Startup(object sender, StartupEventArgs e)
{
bool Absicherung;
Mutex Mutex = new Mutex(true, this.GetType().GUID.ToString(), out Absicherung);
if (Absicherung)
{
Window W = new Loadscreen();
// W.Closed += (sender2, args) => Mutex.Close(); remove this from here
W.Show();
}
.,. Mode code
}
Instead, add it here: (see my comment in the code)
public void Timer_Tick(object sender, EventArgs e)
{
progressBar_Ladebalken.Value = i;
label_Titel.Content = i + "%";
if (i < 100)
{
i += 1;
}
else
{
i = 0;
Timer.Stop();
Window W = new MainWindow();
// add the Close event handler here, and this will ensure your previous
// logic of closing the Mutex when the MainWindow, not the LoadScreen, closes.
W.Closed += (sender, args) => Mutex.Close();
W.Show();
this.Close();
}
}
This should fix your Mutex logic and keep your LoadScreen intact.
On another note, you should use camelCase naming convention for local variables;
Mutex Mutex = new Mutex();
Window W = new MainWindow();
Should be
Mutex mutex = new Mutex();
Window w = new MainWindow();
It is standard across C# this way.
I am making an application using WPF and C#. What I'm trying to do is to print a lots of shapes on a canvas with some time in between when I push a button. At the moment when I push the button, everything just pops up at once. I have tried to sleep the thread for some time between every "print" but that doesn't help, it just take longer time before everything splash up at once. What I want to achive is that the shapes pop up one at a time with lets say 0.5 seconds in between. The code is the following:
private void Create_Click(object sender, RoutedEventArgs e)
{
Random random = new Random();
for (int i = 0; i < 50; i++)
{
Thread.Sleep(500);
Path f = FlowerFactory.createFlower(FlowerBP, true);
Canvas.SetLeft(f, random.Next(0, 1650));
Canvas.SetTop(f, random.Next(0,1000));
DrawBoard.Children.Add(f);
}}
You need to, first, run the loop in a background thread so that it doesn't block the UI from updating; and second, send the UI-rendering tasks back to the UI thread. For the first, you can use Task.Factory.StartNew, and for the second, use Dispatcher.Invoke:
Random random = new Random();
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 50; i++)
{
Thread.Sleep(500);
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
Path f = FlowerFactory.createFlower(FlowerBP, true);
Canvas.SetLeft(f, random.Next(0, 1650));
Canvas.SetTop(f, random.Next(0,1000));
DrawBoard.Children.Add(f);
}));
}
});
It was bad decision to sleep your main thread that responsible for GUI.
Try to use DispatchTimer. For example:
DispatcherTimer m_dispatcherTimer = new DispatcherTimer();
int m_count = 50;
private void Init()
{
m_dispatcherTimer.Tick += new EventHandler(OnTick);
m_dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
private void Create_Click(object sender, RoutedEventArgs e)
{
m_count = 50;
m_dispatcherTimer.Start();
}
private void OnTick(object sender, EventArgs e)
{
// Draw your shapes here
if(0>=--m_count)
{
m_dispatcherTimer.Stop();
}
}
using System.Reactive.Concurrency;
using System.Reactive.Linq;
...
var subscription = Observable.Interval(TimeSpan.FromSeconds(0.5)).Take(50).Subscribe(x=>CreateRandomFlower);
I have an array of five threads. Each thread contains the same form, each form is put on to the screen in a different location (still working on that method :P).
I am trying to have each form load its contents (an image) before the other forms have finishing being placed. At the moment this works for the first form, but the others are blank or disappear :P
Originally each form would be placed but the method would need to finish before all the forms contents were displayed.
Any help would be appreciated, thanks :)
public partial class TrollFrm : Form
{
int number = 0;
public TrollFrm()
{
InitializeComponent();
startThreads();
}
private void TrollFrm_Load(object sender, EventArgs e)
{
}
private void TrollFrm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
public void startThreads()
{
Thread[] ThreadArray = new Thread[5];
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
}
public void createForm()
{
Form frm = new TrollChildFrm();
Random randomX = new Random();
Random randomY = new Random();
number++;
int xValue;
int yValue;
if (number % 2 == 0) //number is even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) + 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) - 200;
}
else //number is not even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) - 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) + 200;
}
frm.Show();
frm.Location = new Point(xValue, yValue);
Thread.Sleep(1000);
}
Your forms are not displaying correctly because they are not running on a thread with a message loop. The general rule is that all UI element accesses must occur on the main UI thread.
Since you have a call to Thread.Sleep(1000) I am going to assume that you want to wait 1 second between the initial display of each form. In that case I would use a System.Windows.Forms.Timer who's Tick event will call createForm directly. Enable the timer, let 5 Tick events come through, and then disable the timer. I see no need to create any threads at all.
The reason your forms aren't displaying is because you are running inside one method on the main UI thread. Instead, you could create a method that spawns a new form and launch that at certain intervals on another thread (making sure the form handling is done on the main UI thread). So you could do something like:
(Pseudo Code)
private const int TIME_THRESHOLD = 100;
int mElapsedTime = 0;
Timer mTimer = new Timer();
.ctor
{
mTimer.Elapsed += mTimer_Elapsed;
}
private void mTimer_Elapsed(...)
{
mElapsedTime++;
if (mElapsedTime >= TIME_THRESHOLD)
{
mElapsedTime = 0;
SpawnForm();
}
}
private void SpawnForm()
{
// Make sure your running on the UI thread
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(SpawnForm));
return;
}
// ... spawn the form ...
}
This is just an example of what I was proposing - it would not look exactly like this in the code, but this should give you an idea of the execution steps.
I would suggest to use Thread.Sleep(1000) in this manner
Caller section
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
Thread.Sleep(1000);
Also in the method that executing the work for the thread.
while(!something)
{
Thread.Sleep(1000)
}
I am writing a WPF C# project with use of BackgroundWorker (a popup window with progress bar).
I start debugging (F5 key) to check my program. After the BackgroundWorker is completed and the popup window is closed, closing the MainWindow does not automatically stop the debugging process. I have to manually hit Shift+F5 to stop the debugging.
I thought BackgroundWorker should have taken care of the Thread automatically. But anyhow, I still call backgroundworker.Dispose() and backgroundworker.CancelAsync() in the RunWorkerCompleted method. And yet, on the closing of the popup window and completion of the BackgroundWorker, I still have to manually do a Shift+F5 to stop debugging.
What is going on in the background that avoid the program from stop debug automatically?
How can I find out?
NOTE: I have made sure the backgroundworker is finished DoWork and completed before I close it. With the popup Window and the BackgroundWorker, it stop debugging automatically the moment I close the Main Window.
[EDIT with codes]
public partial class MainWindow : Window
{
BackgroundWorker backgroundworker1 = new BackgroundWorker();
PopUp pop1 = new PopUp();
public MainWindow()
{
InitializeComponent();
backgroundworker1.DoWork += BackgroundWorker_DoWork;
backgroundworker1.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
backgroundworker1.WorkerReportsProgress = true;
backgroundworker1.ProgressChanged += BackgroundWorker_ProgressChanged;
backgroundworker1.WorkerSupportsCancellation = true;
}
private void startBtn_Click(object sender, RoutedEventArgs e)
{
pop1 = new PopUp();
int iteration = 0;
if (int.TryParse(iterationTb1.Text, out iteration))
{
pop1.Show();
backgroundworker1.Dispose();
backgroundworker1.RunWorkerAsync(iteration);
outputTb1.Text = "running...";
}
}
private void cancelBtn_Click(object sender, RoutedEventArgs e)
{
pop1.Close();
backgroundworker1.CancelAsync();
}
public static int DoSlowProcess(int iterations, BackgroundWorker worker, DoWorkEventArgs e)
{
int result = 0;
for (int i = 0; i <= iterations; i++)
{
if (worker != null)
{
if (worker.CancellationPending)
{
e.Cancel = true;
return result;
}
if (worker.WorkerReportsProgress)
{
int percentComplete = (int)((float)i / (float)iterations * 100);
worker.ReportProgress(percentComplete);
}
}
Thread.Sleep(100);
result = i;
}
return result;
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var bgw = sender as BackgroundWorker;
e.Result = DoSlowProcess((int)e.Argument, bgw, e);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
outputTb1.Text = "Canceled";
}
else
{
outputTb1.Text = e.Result.ToString();
backgroundworker1.CancelAsync();
backgroundworker1.Dispose();
pop1.Close();
pop1.progressBar1.Value = 0;
}
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pop1.progressBar1.Value = e.ProgressPercentage;
pop1.progressLb1.Content = e.ProgressPercentage.ToString();
}
}
OK, I could reproduce your problem and also found the cause.
Change this line:
// PopUp pop1 = new PopUp(); <-- this never-used Win was blocking your close-down.
PopUp pop1 = null;
Because you also have
pop1 = new PopUp();
int iteration = 0;
Creating objects just to initialize a var and later overwriting it is always an anti-pattern. In this case it is actually harmful because you create a Window but never Show() or Close() it.
Note that the Backgroundworker is not involved. It couldn't be, it uses the ThreadPool and that means background Threads. You can close an App with several Backgroundworkers running w/o a problem.