WPF Progress Bar Animation Speed - wpf

I've noticed that there is a difference in the time it takes for a WPF Progress Bar and a WinForms Progress Bar to fill completely.
Fill completely as in set the Value to 100 in both Forms and WPF, one can notice that WinForms fills the bar smoothly whereas the WPF fills it instantly.
I wanted to know if there is a property that we can edit in the templates to change that.
Hope I made it clear, I can post a video too if anyone wants.
EDIT
Here's a video of what I'm talking about, notice the difference ?
EDIT 2
Filling the progress bar with a timer ?
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace WpfApplication2
{
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.Title = "WPF Progress Bar Demo";
}
private void fill(int from, int to)
{
Duration duration = new Duration(TimeSpan.FromSeconds(0.5));
DoubleAnimation doubleanimation = new DoubleAnimation(from, to, duration);
progb.BeginAnimation(ProgressBar.ValueProperty, doubleanimation);
}
private void fill_Click(object sender, RoutedEventArgs e)
{
fill(0, 100);
}
}
}
Is that OK and will it work anywhere ?
Feel free to change it.
Thanks.

The idea is that a progress bar reports actual progress - not time elapsed. It's not intended to be an animation that just indicates something is happening.
The basic principle is that you bind Value to a property on your DataContext class, and update that value whenever a progress milestone occurs.
You can make it fill at a specified rate using a timer - here is an example:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ProgressBar Value="{Binding Path=ProgressValue}"></ProgressBar>
</Grid>
And the code:
public partial class MainWindow : Window, INotifyPropertyChanged
{
Timer timer;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
timer = new Timer();
timer.Interval = 1000;
timer.Elapsed += new ElapsedEventHandler(t_Elapsed);
timer.Start();
}
void t_Elapsed(object sender, ElapsedEventArgs e)
{
if (this._progressValue < 100)
this.ProgressValue = _progressValue + 10;
else
{
timer.Stop();
timer.Dispose();
}
}
private double _progressValue;
public double ProgressValue
{
get { return _progressValue; }
set
{
_progressValue = value;
RaisePropertyChanged("ProgressValue");
}
}
private void RaisePropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
}

See my answer on How to update a progress bar so it increases smoothly?
It's similar to the extension method, but uses a behavior so that you can decouple the progress bar from the thing that's reporting progress. :)

It looks like it's a problem (or not) with only WPF progress bar...another user reported it here
WPF Control, exactly progress bar, does not update itself when
copying When I test to copy a big file, the complete GUI just
completely freezes. The progress bar doesn’t run smoothly. It just
jumps from 0 to 100.
It was solved by adding an extension method:
//Your Code
pbBar.Value = some_value;
pbBar.Refresh();
//Your Code
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
public static void RefreshInput(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Input, EmptyDelegate);
}
}
Calling the Refresh() method after setting the value solved the issue.
But, what I found was even after applying the refresh() method, the progress bar jumps on each run (from different values).
Using a backgroundworker and reportprogress gives the exact result with no "jumps".

Related

Why does WPFMediaKit VideoCaptureElement created by code land ever in MediaFailed?

I add a VideoCaptureElement to a window in runtime but when I run this code it fires MediaFailed. But if I add the same element in XAML then it works fine, I can see the video from the laptop camera.
Am I doing anything wrong? Please help!
public partial class MainWindow : Window
{
WPFMediaKit.DirectShow.Controls.VideoCaptureElement VCE;
public MainWindow()
{
InitializeComponent();
VCE = new WPFMediaKit.DirectShow.Controls.VideoCaptureElement();
Content = VCE;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
VCE.MediaOpened += VCE_MediaOpened;
VCE.MediaFailed += VCE_MediaFailed;
VCE.VideoCaptureDevice = WPFMediaKit.DirectShow.Controls.MultimediaUtil.VideoInputDevices[0]; // This is my laptop webcam
}
void VCE_MediaOpened(Object sender, RoutedEventArgs e) { ... }
void VCE_MediaFailed(object sender, WPFMediaKit.DirectShow.MediaPlayers.MediaFailedEventArgs e) { ... }
}
I had a similar problem with a MediaUriElement working in XAML but not working when instantiated in code-behind.
The solution for me was to Init the control:
VCE.BeginInit();
VCE.EndInit();
This would fit between instantiating (VCE = new...) and assigning (Content = VCE). I haven't tested your particular scenario, but it sounds like the same cause - there must be some extra work done in Init that happens automatically when using XAML.

How to make sure MouseEnter fires for all elements

I have a WPF ItemsControl displaying a series of Rectangles.
Each rectangle makes use of MVVM Lights EventToCommand to track the MouseEnter event and set the Rectangle to 'Selected'
I then use this property to highlight the rectangle using triggers in the style.
My problem occurs if the mouse is dragged too quickly.
Working (Slowly dragged):
Not working (quickly dragged):
In this case the event has not fired for the second Rectangle.
How do I make sure the event fires for all controls the mouse moves over?
My suggestion would be to put all the event occurences in a queue. I think your problem occures because when an event fires, you call one method and if the method hasn't finished at the time the next event occurs, it can not be called a second time.
Create a queue and put the event occures in there, then create a thread that waits for the queue to fill and then procceses it it.
Sample:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApplication3
{
using System.Timers;
using Timer = System.Timers.Timer;
class Program
{
private static Queue<My_Event> EventQueue;
private static Timer t = new Timer(10);
static void Main(string[] args)
{
Task thread = new Task(MarkStuffYellow);
EventQueue = new Queue<My_Event>();
t.Elapsed += t_Elapsed;
t.Start();
t.AutoReset = true;
}
static void t_Elapsed(object sender, ElapsedEventArgs e)
{
EventQueue.Enqueue(new My_Event(sender, e));
}
private static void MarkStuffYellow()
{
/// !!! While (true) is not an solution, if you do it like this,
/// your CPU will be full !!!
while (true)
{
if (EventQueue.Any())
{
My_Event myEvent = EventQueue.Dequeue();
var sender = myEvent.Sender;
var e = myEvent.E;
/// Do Stuff with your event
}
}
}
}
/// Needed to save your event
internal class My_Event
{
public My_Event(object sender, ElapsedEventArgs e)
{
this.Sender = sender;
this.E = e;
}
public object Sender;
public ElapsedEventArgs E;
}
}

Most efficient way of updating "3 minutes ago" type text in WPF

I currently use a valueconverters in XAML to display my viewmodel DateTime fields in "x minutes ago" format. I need to have them updated periodically without causing too much overhead. At any one time I have a dozen on screen, and a few dozen off screen. What is the best strategy?
In the constructor of the viewmodel object, have them register themselves to a static 'ViewRefresher' that periodically goes through all the objects and fires PropertyChanged handlers, on the registered fields.
Refresh the content/items control objects that are holding my objects
Something else?
I will go ahead and try both approaches above while I wait for answers and report back in case it helps someone else.
Update:
OK, thanks to csteinmueller for putting me on the events path. Much cleaner than registering/deregistering objects. I believe the following strategy should not be leaky.
public class DateTimeC: INotifyPropertyChanged
{
public DateTime DT {get; set;}
public event PropertyChangedEventHandler PropertyChanged;
public DateTimeC(DateTime dt)
{
DT = dt;
ViewRefresher.FiveSecondsTick += () =>
{ PropertyChanged(this, new PropertyChangedEventArgs("DT")); };
}
}
public delegate void TickHandler();
public static class ViewRefresher
{
private static DispatcherTimer dt = new DispatcherTimer();
private static int counter = 0;
public static event TickHandler FiveSecondsTick;
public static event TickHandler OneMinuteTick;
static ViewRefresher()
{
dt.Interval = TimeSpan.FromSeconds(5);
dt.Tick += Tick;
dt.Start();
}
private static void Tick(object sender, EventArgs e)
{
if (FiveSecondsTick != null)
FiveSecondsTick();
if (counter++ != 12) return;
counter = 0;
if (OneMinuteTick != null)
OneMinuteTick();
}
}
Would have been nice if I could derive from DateTime directly instead of inlining as a field, but it's sealed.
UPDATE 2: This does seem to have a memory leak after all. You need to unhook event for DateTimeC to be garbage-collected, or use a weak reference.
I would choose a System.Timer object togehther with your first approach (all ViewModels register to a collection or event in a static class)
Timer timer;
AutoResetEvent autoEvent = new AutoResetEvent(true);
TimerCallback callback = new TimerCallback(MyCallback);
timer = new Timer(callback, autoEvent, new TimeSpan(0), new Timespan(5));

TwoWay binding on "linked" variables (Top/Left & Height/Width) with .NET 4.0

I have encounted a problem when switching to the .NET Framework 4.0.
I have a window that uses twoway binding on its Top/Left & Widht/Height properties.
A problem occurs when i need to change the viewModel.
After changing the underlying ViewModel, when triggering the PropertyChanged event on the propertyname corresponding to my viewModel, the Left property's binding is triggered, moving the window to the correct X-location.
But the action of moving the window triggers a "to source", setting my viewModel's Top property.
EDIT : There is not "set" done, but the Y Binding is not processed.
Same behavior with the Height & Width properties.
Here is a tiny application that shows my problem.
here is the model :
public class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Position SelectedPos { get; set; }
public Position Pos1 { get; set; }
public Position Pos2 { get; set; }
public Model( int x, int y, int x2, int y2 )
{
Pos1 = new Position( x, y );
Pos2 = new Position( x2, y2 );
SelectedPos = Pos1;
}
public void Toggle()
{
SelectedPos = Pos2;
if( PropertyChanged != null )
{
var e = new PropertyChangedEventArgs( "SelectedPos" );
PropertyChanged( this, e );
}
}
}
public class Position
{
int _x;
public int X
{
get { return _x; }
set { _x = value; }
}
int _y;
public int Y
{
get { return _y; }
set { _y = value; }
}
public Position( int x, int y )
{
X = x;
Y = y;
}
}
And here is the view :
<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="350" Width="525"
Left="{Binding Mode=TwoWay, Path=SelectedPos.X}"
Top="{Binding Mode=TwoWay, Path=SelectedPos.Y}">
<Grid>
<Button Click="Button_Click">Change Position</Button>
</Grid>
</Window>
And finally the code-behind :
namespace WpfApplication1
{
public partial class MainWindow : Window
{
Model model;
public MainWindow()
{
InitializeComponent();
model = new Model( 5, 5, 500, 500 );
DataContext = model;
}
private void Button_Click( object sender, RoutedEventArgs e )
{
model.Toggle();
}
}
}
What I would've liked to know is if there is some kind a way to "freeze" a binding, to prevent the engine from setting my viewModel until it has finished processing all the binding I asked it to do. or to switch the binding from twoWay to OneWay, for a short period of time.
The small application here behaves correctly when using the .NET framework 3.5 but doesn't
with the 4.0.
I am surprised I couldn't find anyone struggling with the same issue, am i doing something wrong ?
I thank you for your answers, don't hesitate to ask if something is not clear.
Jean-Loup Kahloun
I've added logs this morning (i should've done that before posting here..), just like you did, and you are right, there is no "set" done, but the Y binding is not processed.
The behavior is even more strange when actually toggling several times the position of the window.
I'm going to test your solution, even though I would have liked to avoid using code behind ( I used some for test purposes only ).
I thank you for answering so fast, i'll get back at you when I have some time to find a code-behind-free solution.
As the model is not set, i may be able to trigger seperately the X and Y bindings with propertychanged events, right after the weird-behaving "Position" binding is triggered.
Thanks again, i was going the wrong way, you saved me loads of time.
I'm not sure I agree with your point
But the action of moving the window triggers a "to source", setting my viewModel's Top property.
I have run your code and I can confirm that the window moves from (5, 5) to (500, 5) when you click the 'Change Position' button. However, I then added another button whose Click event handler wrote the values of the window's Left and Top values to the debug log. I found that this reported that the window was apparently at (500, 500). I then dragged it a short distance, clicked this button again and was then informed that the window was at (498, 4).
I think the bindings are working correctly, but for some reason, Windows doesn't move the window when its Left and Top properties both change via bindings in quick succession. I'm not sure why this happens; it could be a bug in .NET 4, especially if it worked in .NET 3.5.
I found that the window behaved a bit more as I would expect it to if I added a dependency property of type Position and bound that direct to SelectedPos rather than binding the window's Left and Top properties to the individual X and Y coordinates inside SelectedPos. When this dependency property changed, I set the window's Left and Top values to the X and Y values within the Position.
The dependency property and property-changed callback I added was as follows:
public Position WindowPosition
{
get { return (Position)GetValue(WindowPositionProperty); }
set { SetValue(WindowPositionProperty, value); }
}
public static readonly DependencyProperty WindowPositionProperty =
DependencyProperty.Register("WindowPosition", typeof(Position), typeof(MainWindow), new PropertyMetadata(WindowPosition_Changed));
private static void WindowPosition_Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var mainWindow = obj as MainWindow;
mainWindow.Left = mainWindow.WindowPosition.X;
mainWindow.Top = mainWindow.WindowPosition.Y;
}
I found that the binding had to be made in code-behind. I added this line to the MainWindow constructor:
SetBinding(WindowPositionProperty, new Binding("SelectedPos"));
Finally, I deleted the bindings on Left and Top in the main window.

WPF not releasing memory

I have a issue in our application where the memory is not released when the user controls
are unloaded. This will increase the memory starting from 40MB and ends up with 200MB and more.
To simulate this,
I created a wpf project which has the main window and a user control
loaded 1000 objects into a wpf datagrid which is placed in a user control
A scroll viewer is put in the main window
The user control is loaded inside this scroll viewer Once the show button is clicked
The user control is removed from the Content of the Scroll viwer once the Close button is clicked
Once i checked with the task manager, before the 1000 objects are loaded to the grid, the memory consumption is 14MB. Once its loaded by clicking on the show button it increases to 70MB. But when i click on Close button to remove the user control from the window, the memory reduces to 67MB only. Shouldn't it reduce to 14BMB or something close to that??
When i checked this with the ANTS memory profiler, it shows that the 1000 objects remain in memory even after the User control is removed from the Window. Shouldn't the garbage collector release these objects when the user control is removed from the window (once the Scroll viewer Content Property is set to null)?
Following is the Code i used for this. I didn't use any styles, data templates or any third party controls, only used the WPF DataGrid control to load the data.
The User Control Code Behind
public partial class UserControl1 : UserControl,IDisposable
{
List<TestClass> list = null;
public UserControl1()
{
InitializeComponent();
}
public void Dispose()
{
BindingOperations.ClearBinding(dgList, DataGrid.ItemsSourceProperty);
list.Clear();
GC.Collect();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
list = new List<TestClass>();
for (int i = 0; i < 1000; i++)
{
TestClass obj = new TestClass();
obj.Name = "test name";
obj.Age = 34;
list.Add(obj);
}
dgList.ItemsSource = list;
}
}
public class TestClass
{
public string Name { get; set; }
public int Age { get; set; }
}
Main Window Code behind
public partial class MainWindow : Window
{
UserControl1 control = null;
public MainWindow()
{
InitializeComponent();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
control.Dispose();
scwContent.Content = null;
control = null;
}
private void btnShow_Click(object sender, RoutedEventArgs e)
{
control = new UserControl1();
scwContent.Content = control;
}
}
Thanks.
The Garbage collector only collects when memory is needed, not when references are set to null.
(Only exception: calling GC.Collect())
Why are you trying to call GC? That is not required
Change
for (int i = 0; i < 1000; i++)
{
TestClass obj = new TestClass();
...
To
TestClass obj;
for (int i = 0; i < 1000; i++)
{
obj = new TestClass();
...
You can set the list object to null ..
Read this for understanding setting objects to null
Setting an object to null vs Dispose()

Resources