I'm building a very simple C# WPF Application. What the app does is that when I press a button it shows a value randomly from an string list.
What I would like to achieve is a animation where it quickly scrolls through all the values from the list (displaying in a label) and then start to slow down and stop on a random string from the list. Almost as a "spinning/scrolling/flashing wheel of text".
I'm still very new to programming (second day of C# learning) so would be glad if someone could point me in the right direction. Loop with timer?
List<string> randomStrings = new List<string>();
public MainWindow()
{
InitializeComponent();
randomString.Add("Abcd");
randomString.Add("Water");
randomString.Add("Moon");
randomString.Add("Pizza");
randomString.Add("Winter");
randomString.Add("Orange");
MyRandomStrings.ItemsSource = randomString; //Showing which strings in box.
}
public void GetRandomString()
{
Random r = new Random();
int index = r.Next(randomString.Count);
string myRandomString = randomString[index]; //Fetch a random string
Result.Content = myRandomString; //Sets the label. I want this to be "animated".
}
private void Button_Click(object sender, RoutedEventArgs e)
{
GetRandomString();
}
You could use a Task.Delay to create a delay and still create sequential code instead of a statemachine or timers etc.
Here is an example:
It uses a Label and a Button on a WindowsForm. So with a little ajustment, you can make it work on your configuration.
public partial class MainWindow : Form
{
private List<string> _randomStrings = new List<string>();
private Random _rnd = new Random(DateTime.UtcNow.Millisecond);
public MainWindow()
{
InitializeComponent();
_randomStrings.Add("Abcd");
_randomStrings.Add("Water");
_randomStrings.Add("Moon");
_randomStrings.Add("Pizza");
_randomStrings.Add("Winter");
_randomStrings.Add("Orange");
}
private async void button1_Click(object sender, EventArgs e)
{
// determine the rollcount. (some initial rolls for the rolling effect)
int rollCount = 50 + _rnd.Next(_randomStrings.Count);
int index = 0;
// roll it.......
for (int i = 0; i < rollCount; i++)
{
// just use a modulo on the i to get an index which is inside the list.
index = i % _randomStrings.Count;
// display the current item
label1.Text = _randomStrings[index];
// calculate a delay which gets longer and longer each roll.
var delay = (250 * i / rollCount);
// wait some. (but don't block the UI)
await Task.Delay(delay);
}
MessageBox.Show($"and.... The winner is... {_randomStrings[index]}");
}
}
Related
I'm sorry to ask you a basic question first. It hasn't been long since I learned C#.
private void numberButton_Click(object sender, EventArgs e)
{
Random rand = new Random();
int randNumber = rand.Next(1, 1000);
randomNumber.Text = randNumber.ToString();
bestScoreLabel.Text = randomNumber.Text;
}
How can I implement the function so that the maximum value of the bestScoreLabel is automatically updated when I click the number button as shown in the picture above?
Currently, the code is configured as above, but the problem occurs that the maximum and current values are the same output.
The idea is to have a variable to keep tracking the max number.
private static int _maxNumber = 0;
private void numberButton_Click(object sender, EventArgs e){
Random rand = new Random();
int randNumber = rand.Next(1, 1000);
randomNumber.Text = randNumber.ToString();
if (_maxNumber < randNumber)
{
_maxNumber = randNUmber;
}
bestScoreLabel.Text = _maxNumber.ToString();
}
Bear with me, I'm new to Stack Overflow, but have used it as a resource for a long time when researching methods of programming that I'm not fond with.
I read up a tutorial on how to create a graph in a C# Windows Forms Application, and was attempting to find out how to make it update itself in real-time if I ever need to use the graph to plot the total amount of data in a sensor. To test it out, I'm using a timer, ticking at every second (1000ms). And before I can use this with a sensor, I'm having two values automatically increment by 1.
The current problem I'm facing is that the chart itself won't update, and only stays the way it was drawn when the form loaded. I thought it was because I have to redraw the chart with chart1.Update();, and I tried using that before/after recreating the chart every second. However, the result is the same regardless. I just wondered if there's something I haven't done or needs to be changed in order to update the chart in real-time.
This is where the code is at currently:
public partial class Form1 : Form
{
int a = 1;
int b = 2;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Data arrays.
string[] seriesArray = { "Cats", "Dogs" };
int[] pointsArray = { a, b };
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series.
for (int i = 0; i < seriesArray.Length; i++)
{
// Add series.
Series series = this.chart1.Series.Add(seriesArray[i]);
// Add point.
series.Points.Add(pointsArray[i]);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
a++;
b++;
// Data arrays.
string[] seriesArray = { "Cats", "Dogs" };
int[] pointsArray = { a, b };
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series.
for (int i = 0; i < seriesArray.Length; i++)
{
// Add series.
Series series = this.chart1.Series.Add(seriesArray[i]);
// Add point.
series.Points.Add(pointsArray[i]);
}
chart1.Update();
}
}
Your code has several problems:
The timer click event is not hooked up. I know that it isn't because otherwise you'd get an exception telling you that..
..you can add a series only once. You were doing it on each timer.Tick. This and all other setup commands should go into an initial method like the form load.
I have corrected the errors in the code below, but, obviously, the data don't make any sense yet.
Also: While I have added code to hook up the timer.Tick, the button.Click is not hooked up. Usually you let the designer do this by double-clicking the control to hook up the standard event of a control or by double-clicking the event in the control's event tab in the property page.
int a = 1;
int b = 2;
string[] seriesArray = { "Cats", "Dogs" };
private void Form1_Load(object sender, EventArgs e)
{
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series
this.chart1.Series.Clear();
for (int i = 0; i < seriesArray.Length; i++)
{
chart1.Series.Add(seriesArray[i]);
}
// hook up timer event
timer1.Tick += timer1_Tick;
}
private void timer1_Tick(object sender, EventArgs e)
{
a++;
b++;
// Data array
int[] pointsArray = { a, b };
for (int i = 0; i < seriesArray.Length; i++)
{
// Add point.
chart1.Series[i].Points.Add(pointsArray[i]);
}
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
How to run a method exactly ten times in csharp?
I'm writing a c#/xaml windows8 app, and I want to run some method for button exatcly 10 times, and when it is called 10th time, I want it to go on to another method that will execute itself.
My button in XAML leads to this method I want to use ten times, to get 10 different images every time (I still haven't figured how to get different images every time because if-else loop in this method is infinite):
public void LoadImage_Click_1(object sender, RoutedEventArgs e)
{
Random rand = new Random();
int pic = rand.Next(1,0)
myImage.Source = new BitmapImage(new Uri("ms-appx:///img/" + pic +".jpg"));
}
and after it runs for the 10th time I want to use another method on the same button
As mentioned, this can be accomplished using a simple counter.
private volatile int _loadImageCount = 0;
public void LoadImage_Click_1(object sender, RoutedEventArgs e)
{
_loadImageCount += 1;
if (_loadImageCount > 10)
{
UpdateImage();
}
else
{
UpdateRandomImage();
}
}
private void UpdateRandomImage()
{
Random rand = new Random();
int pic = rand.Next(1,0)
myImage.Source = new BitmapImage(new Uri("ms-appx:///img/" + pic +".jpg"));
}
private void UpdateImage()
{
...
}
int numberOfExecutions=0;
public void LoadImage_Click_1(object sender, RoutedEventArgs e)
{
if(numberOfExecutions < 10)
{
Random rand = new Random();
int pic = rand.Next(1,0);
myImage.Source = new BitmapImage(new Uri("ms-appx:///img/" + pic +".jpg"));
}
else
MessageBox.Show("Dududu!");
numberOfExecutions++;
}
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)
}