Delayed Source Binding

Consider the following ViewModel property:

private string _slowProperty; public string SlowProperty { get { return _slowProperty; } set { _slowProperty = value; RaisePropertyChanged("SlowProperty"); } } 

What is associated with the text box, for example:

 <TextBox Text="{Binding SlowProperty}" /> 

Now the problem is that every time the SlowProperty value changes, and this happens quite often, the text field goes and tries to get its value, which is pretty slow. However, I could alleviate the situation by using asynchronous binding, which would still waste processor cycles.

Instead, what I would like to have is something like:

 <TextBlock Text="{z:DelayedSourceBinding SlowProperty}" /> 

Which will try to get a binding after some delay. So, for example, if SlowProperty changed 5 times in a row, only the last text will be displayed in the text box for a short time.

I found the following project that does something similar, so in my example, I could use it like this:

 <TextBox Text="{z:DelayBinding Path=SearchText}" /> 

The problem with it is that it only updates the target binding after the delay. The source path, however, is evaluated, and its destination is executed each time the source changes. Which in the case of SlowProperty will still spend CPU cycles.

I tried to make my own deferred binding class, but stuck . Is there any other binder that can do something like this?

For completeness, there are 2 more projects that perform similar tasks, but none of them address the problem that I am experiencing:

DeferredBinding is a similar solution for DelayBinding. However, it is a little harder to use.

DelayedBindingTextBox - Implements delayed binding using a custom text field control.

Thanks!

+7
source share
4 answers

Why not solve this problem in the view model? If your property changes quickly, but it is slower, you can get the second "delayed" property, which will be displayed by your view model. You can use a timer to periodically update this "delayed" property.

Or a cleaner implementation might use the Throttle feature provided by the reactive extension infrastructure.

+3
source

I had a similar requirement some time ago, where I needed to delay both the source and the target, so I created two markup extensions called DelayBinding and DelayMultiBinding . To defer updating to source, you specify UpdateSourceDelay

 <TextBox Text="{db:DelayBinding SlowProperty, UpdateSourceDelay='00:00:01'}" /> 

The source code and sample use for DelayBinding and DelayMultiBinding can be downloaded here .
If you are interested in implementation details, you can check out my blog about it here:
DelayBinding and DelayMultiBinding with source and target delay

+2
source

It seems to me that what you really want is to delay the point when RaisePropertyChanged () is called.
So I tried this and here is the solution:

XAML:

 <StackPanel> <TextBox Text="{Binding DelayedText, UpdateSourceTrigger=PropertyChanged}" /> <TextBlock Text="{Binding DelayedText}" /> </StackPanel> 

FROM#:

 public partial class MainWindow : Window, INotifyPropertyChanged { public MainWindow() { InitializeComponent(); this.DataContext = this; } private String m_DelayedText; public String DelayedText { get { return m_DelayedText; } set { if (m_DelayedText != value) { String delayedText; m_DelayedText = delayedText = value; Task.Factory.StartNew(() => { Thread.Sleep(2000); if (delayedText == m_DelayedText) { RaisePropertyChanged("DelayedText"); } }); } } } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(String _Prop) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(_Prop)); } } } 

You can check if this works by setting a breakpoint in RaisePropertyChanged("DelayedText")

I understand that this may look like quite a lot of code for a “simple” property.
But you can use code snippets or enter template code at runtime using Resharper, etc.
In general, you probably won't need it that often.

In addition, if you used a different approach (for example, by setting up the TextBox), you will have to handle all the places where you are attached to the property.
Thus, in the property adjuster, you guarantee that everyone who accesses this property will be limited to received updates.

NTN

Women.

+1
source

It should be noted that with .Net 4.5, the delay property is added to the infrastructure, which allows you to set the value of the binding delay in milliseconds. The Microsoft example emphasizes twoway mode, but bind delay works in any bind mode.

For example, I used this in a datagrid, where the selected item / value had to be changed both from a text field in the user's user control, and, obviously, from inside the datagrid. For reasons that I will not mention here, the text field should have been attached to a property different from the presentation model, but both properties should have the same value at the end of the day, and any change in one of them should have been reflected in friend. When the selected value changed in the datagrid, it was also necessary to update the text box, and I checked the actual changes in the values ​​in the installer of the SelectedValue property to prevent infinite looping. When the change was too quick, an error occurred saving the data back to the source text when the text was changed inside the text field, which was changed by the SelectedValue installer. A two-frame delay fixed the problem without any complicated solutions and without feeling the UI too laggy:

 SelectedValue="{Binding SampleNumberSelect, Mode=OneWayToSource, Delay=33}" 

This is very convenient and eliminates the need to make any such changes to the presentation model, which unnecessarily clutters the code, including the need to control any timers when closing the window. Of course, it doesn’t even need to be used in a relatively complex scenario like mine, but it can be useful to prevent the CPU / resource code from running unnecessarily with every small change in the user interface.

+1
source

All Articles