Reputation: 793
I Have an issue with my DependencyProperty. Say you have a timer that updates some UI element, if the callback is called once every 100ms which in turn updates the UI then i have no problem, however, if the timer is set to ~10ms for example, some of the calls will get ignored. I made a small solution that reproduces the problem:
This is a Custom UIElement with a dependency property:
public class CustomLabel : Label
{
public float Range
{
get { return (float)GetValue(MaxRangeProperty); }
set { SetValue(MaxRangeProperty, value); }
}
public static readonly DependencyProperty MaxRangeProperty =
DependencyProperty.Register("Range", typeof(float), typeof(CustomLabel),
new PropertyMetadata(0f, RangePropertyChanged));
private static void RangePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var self = d as CustomLabel;
Debug.WriteLine("CustomLabel");
self.Content = self.Range;
}
}
This is a ViewModel that fires a timer and updates a property which in turn should call the CallBack on the DependencyProperty on CustomLabel.
public class ViewModel : INotifyPropertyChanged
{
Timer timer;
Thread t;
public ViewModel()
{
t = new Thread(() => timer = new Timer(new TimerCallback(CallBack), null, 0, 10));
t.Start();
Range = 100;
}
void CallBack(object state)
{
Range = (new Random()).Next(0, 1000);
}
private float _range;
public float Range
{
get { return _range; }
set
{
if (_range != value)
{
_range = value;
NotifyPropertyChanged();
Debug.WriteLine("ViewModel");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And this is my View where the CustomLabel lives and the ViewModel:
<Window x:Class="TimerTest.MainWindow"
xmlns:local="clr-namespace:TimerTest"
Title="MainWindow">
<Grid>
<local:CustomLabel x:Name="customLabel" Range="{Binding Range}"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel = new ViewModel();
customLabel.DataContext = ViewModel;
}
public ViewModel ViewModel { get; set; }
}
So, I made some Debug.WriteLine()
statements on each side of the DependencyProperty, the output looks like this:
100ms 10ms
CustomLabel ViewModel
ViewModel CustomLabel
CustomLabel ViewModel
ViewModel ViewModel
CustomLabel CustomLabel
ViewModel ViewModel
CustomLabel ViewModel
ViewModel ViewModel
CustomLabel ViewModel
ViewModel CustomLabel
Why is this happening and what can I do about it? Thanks for your time.
Upvotes: 3
Views: 521
Reputation: 10744
The NotifyPropertyChanged
event is handled by the Dispatcher
, which uses a queue. The dispatcher is processing the events at a slower rate than they are being added to the queue.
Using a DispatcherTimer
might allow you to update faster:
DispatcherTimer timer =
new DispatcherTimer(TimeSpan.FromMilliseconds(10),
DispatcherPriority.Normal,
delegate
{
MyCustomLabel.SetValue(MaxRangeProperty, viewModel.Range);
},
Dispatcher);
Also...
The System.Threading.Timer class that you are using does not, by default, have an accuracy capable of 10ms. It will use the operating system timer.
Quoting a Microsoft document on timer resolution:
The default timer resolution on Windows 7 is 15.6 milliseconds (ms)
It is possible to increase the timer resolution using calls to the Windows API, but this can cause battery drain.
Upvotes: 1