I want to implement a statusbar where i will be able to display messages for a specified period of time after which they will fadeout.
Can this be done with any ready made control in wpf? I can't find such a functionality in StatusBar which as far as i understand is a container of other items.
Any suggestions?
StatusBar is indeed only a container of other items.
I think there isn't any built-in functionality like this.
But you can use a Timer to achieve what you want.
Make a method that sets the text message as the content of a StatusBarItem, set a time in the Timer and in the Timer.Elapsed event you remove the text from the StatusBarItem.
StatusBar XAML:
<StatusBar Height="25" Margin="5">
<StatusBarItem x:Name="StatusMessage" />
</StatusBar>
Procedural code:
private void ShowStatusMessage(string message)
{
StatusMessage.Content = message;
var timer = new System.Timers.Timer();
timer.Interval = 2000; //2 seconds
timer.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e)
{
//stop the timer
timer.Stop();
//remove the StatusMessage text using a dispatcher, because timer operates in another thread
this.Dispatcher.BeginInvoke(new Action(() =>
{
StatusMessage.Content = "";
}));
};
timer.Start();
}
If you want to animate you should look for DoubleAnimation
Just bind the data in the progress bar and update it whenever faded out. Let us know more details for giving better solutions
Related
I've got a problem while programming a little game for myself.
I'm using the "System.Timers"-Timer and want to decrease the value of a progress bar
by every tick of the timer. There I faced my problem. I can't set a custom event handler to decrease the value of the progress bar.
I've using for the Timer the following code:
private Timer t = new Timer();
t.Interval = 600000;
t.Elapsed += Ended; //For ending event
t.AutoReset = true;
So how can I register a tick to decrease the value of the progress bar.
Thank you for your answers in advance.
Greetings
SirCodiac
You cant invoke a control from system.timers. In order to invoke the progress bar either use System.Windows.Forms.Timer or use a MethodInvoker as below:
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (progressBar1.InvokeRequired)
{
progressBar1.Invoke(new MethodInvoker(delegate { progressBar1.Value++; }));
}
else
{
progressBar1.Value++;
}
}
I am teaching myself C# and, as part of this, am trying to develop an iOS countdown timer app that is to play a .wav sound file X seconds after a timer initiating button has been clicked as the timer value has gone from X to 0.
In an attempt to do this I have tried using the System.Timers namespace but have been unable to figure out how to program the countdown timer described above. Below is my incomplete code (code that obviously does not fulfill the above described function but might be a part of the full code that would fulfill that function):
partial void UIButton1416_TouchUpInside(UIButton sender)
{
url = NSUrl.FromFilename("Sounds/bell.wav");
bell = new SystemSound(url);
int RoundedTimerValue = Convert.ToInt32(Math.Round(TimerSlider.Value, 0));
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 60000;
timer.Enabled = true;
}
Does anyone know how to create the described countdown timer / Trigger an event X seconds after a button has been clicked?
Example Code.
Timer timer = new Timer();
timer.Interval = 60000;
timer.Elapsed += new ElapsedEventHandler((x,y) => {
//Do whatever you want
timer.Stop();
});
Put the below code in the Button Click Handler and make the timer variable global.
timer.Start();
Or you can leave everything in the Button's click handler, not a big deal.
Explanation:
The timer class has an event called Elapsed which is called when the specified number of milliseconds in the timer's Interval gets over. with the line
timer.Elapsed += new ElapsedEventHandler((x,y) => {...
we are assigning a Delegate(Virtual function) to be called when the timer is up. therefore any code within the braces{} will be called at every Timer.Interval milliseconds. we stop the timer at that time as we don't want it to keep running and generate a lot of events.
Update 2:
Normally , EventHandlers are Defined using
return_type functionName(object sender, EventArgs e);
But since the delegate is virtual, so is the parameter. x corresponds to sender and y corresponds to e.
that event handler code can also be written as below
void someFunction(object sender, ElapsedEventArgs e)
{
timer.Stop();
}
and then,
timer.Elapsed += new ElapsedEventHandler(someFunction);
As for the '=>' you can read about Lambda Expressions Here
I'm learning how to webscrape in WPF. I check the site every 20sec, update my ObservableCollection (myClients) according to search results and display it in Listview (myList). I have 2 Buttons, one to start search and one to stop it.
I didn't know how to implement button autoclick every X sec (which would solve all my problems, am i right?) so i had to use Task.Delay(20000). Program works, it doesn't freeze right at the start like if i had used Thread.Sleep(), but if i press the Stop button and then Start, everything freezes.
I will upload only portion of the code that seems to be the problem. Note that the whole program at the moment is mostly reverse-engineered from several different programs as i am still a beginner.
private async void Button_Click(object sender, RoutedEventArgs e) //Start button
{
string car;
string price;
string link;
wantToAbort = false;
while (!wantToAbort)
{
// ----Simulate GET request----
//-----End GET----
myList.ItemsSource = myClients;
string searchCar = txtBlock.Text + " " + txtBlock2.Text;
var articleNodes = htmlDoc.DocumentNode.SelectNodes($"//*[#id='main_content']/div[1]/div[2]/ul[1]//*[text()[contains(., '{searchCar}')]]");
if (articleNodes != null && articleNodes.Any())
{
foreach (var articleNode in articleNodes)
{
car = WebUtility.HtmlDecode(articleNode.InnerText);
price = WebUtility.HtmlDecode(articleNode.ParentNode.ParentNode.SelectSingleNode("span").InnerText);
link = WebUtility.HtmlDecode(articleNode.ParentNode.ParentNode.Attributes["href"].Value);
var tempUser = new User(car, price, link);
if (!myClients.Any(x=>x.Link == tempUser.Link))
{
myClients.Insert(0, tempUser); //Inserts new item if Links are different
txtBlock3.Text = "Searching...";
}
}
await Task.Delay(20000); //This seems to be an issue
}
}
}
private void Button_Click_1(object sender, RoutedEventArgs e) //Stop button
{
wantToAbort = true;
txtBlock3.Text = "Ready to search again!";
}
Running a while loop on the UI thread may freeze the application as the UI thread cannot both process UI events and execute a loop or doing anything else simultaneously.
If you want to do something every x seconds you could use a timer as suggested by EJoshuaS. There is a DispatcherTimer class in WPF that fires a Tick event on the UI thread at an interval specified by the Interval property: https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer%28v=vs.110%29.aspx
You don't want to perform the GET request to the web server on the UI thread though so you should probably use a System.Timer.Timer: https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx. This is a different type of timer that runs on a background thread.
Since you can only access UI controls such as TextBlocks and ListBoxes on the thread on which they were originally created - that is the UI thread - you will have to use the dispatcher to marshall any code that access these controls back to the UI thread in your Elapsed event handler:
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
//call the web server here....
//dispatch any access to any UI control
txtBlock3.Dispatcher.Invoke(new Action(() = > { txtBlock3.Text = "Searching..."; }));
}
The golden rule to maintain a responsive application is to execute any long-running code on a background thread but you must only access UI controls back on the UI thread. Please refer to MSDN for more information about the threading model in WPF: https://msdn.microsoft.com/en-us/library/ms741870(v=vs.110).aspx
DispatcherTimer may be a better solution in this case, like in the below example:
public partial class MainWindow : Window
{
private DispatcherTimer timer;
public MainWindow()
{
InitializeComponent();
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 220);
timer.Tick += Timer_Tick;
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
// Do something on your UI
Trace.TraceInformation("Timer expired");
}
}
Basically, this will raise an event at a given interval. Note that Windows Forms also has a timer, as does System.Threading, but you want to make sure you use DispatcherTimer rather than those. In particular, the one from System.Threading tends not to mix well with UIs because it runs its actions on the thread pool and WPF in particular is very fussy about how you update your UI from background threads.
The documentation I link to, as well as this answer, also give details on this.
In my WPF application i have to show a progressbar progress with in a timer tick event, which i am writing as below,
System.Windows.Forms.Timer timer;
public MainWindow()
{
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
this.timer.Tick += new System.EventHandler(this.timer_Tick);
}
load event as below
private void Window_Loaded(object sender, RoutedEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Value = DateTime.Now.Second;
progressBar1.Maximum = 700;
timer.Start();
}
And at last in tick event,
private void timer_Tick(object sender, EventArgs e)
{
Duration duration = new Duration(TimeSpan.FromSeconds(20));
//progress bar animation
System.Windows.Media.Animation.DoubleAnimation doubleanimation = new System.Windows.Media.Animation.DoubleAnimation(200.0, duration);
progressBar1.BeginAnimation(ProgressBar.ValueProperty, doubleanimation);
}
When the program's progressbar shows the progress for two-three bars and then it stops increment. Later there is no effect in the progress at all.
Why?
Since your ProgressBar doesn't relate to any particular behavior, it looks like a job for an indeterminate bar.
This other SO question provides some insight about it. In short, it's a XAML one-liner:
<!-- MinVal, MaxVal, Height needed for this to work -->
<ProgressBar x:Name="progressBar1" Margin="5" IsIndeterminate="True"
MinimumValue="0" MaximumValue="700" value="0" Height="20"/>
Then in code, you go like this:
progressBar1.IsIndeterminate = true; // start animation
progressBar1.IsIndeterminate = false; // stop animation
In my WPF application I have ... System.Windows.Forms.Timer timer;
That is the wrong type of timer. Use a DispatcherTimer instead.
When i execute my program progressbar shows the progress for two-three bars and then it stops
This surprises me, I wouldn't have expected it to work at all. This means you may have other problems too, like blocking the main (dispatcher) thread.
You are only setting the Value once, in the Loaded event:
progressBar1.Value = DateTime.Now.Second;
There is no change to progressBar1.Value in the Tick event. So it figures that it stops moving.
Use DispatcherTimer instead of Timer (Forms object), and use Value property of ProgressBar.
Try this:
MainWindows.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="55" Width="261">
<Grid>
<ProgressBar Name="pb" Maximum="60" />
</Grid>
</Window>
MainWindows.xaml.cs:
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private DispatcherTimer timer;
public MainWindow()
{
InitializeComponent();
this.timer = new DispatcherTimer();
this.timer.Tick += timer_Tick;
this.timer.Interval = new System.TimeSpan(0, 0, 1);
this.timer.Start();
}
private void timer_Tick(object sender, System.EventArgs e)
{
this.pb.Value = System.DateTime.Now.Second % 100;
}
}
}
You can change the behaviour of the progress bar by changing the Value property (don't forget defining the Maximum property in the xaml).
I found this (WPF Multithreading: Using the BackgroundWorker and Reporting the Progress to the UI. link) to contain a great solution for my needs, albeit with a dialog box.
The one thing I found very useful was that the worker thread couldn't access the MainWindow's controls (in its own method). However, when using a delegate inside the main windows event handler, it was possible.
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
pd.Close();
// Get a result from the asynchronous worker
T t = (t)args.Result
this.ExampleControl.Text = t.BlaBla;
};
I'm trying to figure out a way in Silverlight / C# to make a DispatchTimer run only once.
I have a user form and when submitted I want to display a message for 10 seconds and then disappear and kill the DispatchTimer thread.
I know how to make a DispatchTimer that repeats:
clock.Interval = TimeSpan.FromSeconds(10);
clock.Tick += clockTick;
clock.Start();
But I want that thread to end as soon as it completes.
This should work for you:
DispatcherTimer clock = new DispatcherTimer();
clock.Interval = TimeSpan.FromSeconds(10);
clock.Tick += (object sender, EventArgs e) =>
{
clock.Stop();
// Some code here
};
clock.Start();
An anonymous event handler will also keep things "in the same place" in case you don't want to widen the scope of your DispatcherTimer object.
Stop the timer in your clockTick handler once it fires.