Is there an easy way to tell a Two-way WPF data binding to wait a few milliseconds after the last change before updating the Source with the new property value?
I'm implementing a filter feature for a ListBox where I have a textbox, and I want to filter the content of the ListBox according to what I type. I'm using data binding to connect the pieces together. Filtering the list can be quite time consuming, so I don't want to do it after every character that is typed: hence my request.
I have been using Paul Stovell's DelayBinding Extension (his site's down at the moment, so I can't link to it). However, I suspect that it is the cause of a memory leak in my applicataion (caused by it not removing event handlers).
Does anybody else have any other ideas?
I'm also a few years late, but if you're using WPF 4.5+ there is now an property exactly for this purpose, it's called Delay.
Description
The amount of time, in milliseconds, to wait before updating the
binding source.
Example usage
<TextBlock Text="{Binding Name, Delay=500}"/>
A little late to the question here (just a few years :) but for anyone who's interested I had a similar requirement in a project so I created two markup extensions called DelayBindingExtension and DelayMultiBindingExtension.
They work like normal Bindings with the addition that you can specify UpdateSourceDelay and/or UpdateTargetDelay, both of which are TimeSpan properties. Also, I've verified that it's leak-free (it makes use of the propertychanged callback of a dependency property binding through inheritance context rather than the DependencyPropertyDescriptor).
Example usage for a DelayBinding
<TextBox Text="{db:DelayBinding Path=TextProperty,
UpdateSourceTrigger=PropertyChanged,
UpdateSourceDelay='00:00:01'}"/>
And for a DelayMultiBinding
<cs:ColorSelector.SelectedColor>
<db:DelayMultiBinding Mode="TwoWay"
Converter="{StaticResource ColorConverter}"
UpdateSourceDelay="00:00:02"
UpdateTargetDelay="00:00:01">
<Binding Path="Red" />
<Binding Path="Green" />
<Binding Path="Blue" />
</db:DelayMultiBinding>
</cs:ColorSelector.SelectedColor>
Source code and sample usage for DelayBinding and DelayMultiBinding can be downloaded here.
If you're interested in the implementation details, you can check out my blog post about it here: DelayBinding and DelayMultiBinding with Source and Target delay
First, to answer your question, I would add the UpdateSourceTrigger binding extension which will let you control when the binding updates. Try LostFocus first but it sounds like you might want to go for Explicit.
Second, if your filtering takes a long time I would look into using CollectionViewSource on your ListBox. Bea Stollnitz has a good primer on it here and I used this blog post to show me how to filter. When I changed over I noticed a huge speed difference over my other implementation even though they use the same filtering functions. Also CollectionViewSource will automatically handle updating filtered items if the list you're bound to changes, even on the item level if you're binding to an ObservableCollection (this is the original reason I changed to CollectionViewSource).
HTH
Related
I have two User Controls in my window, both are bound to the same context.
One of them is getting updated and the other is not.
What could be the reason?
Sounds like you have an issue with the bindings. Make sure your dependency properties bound to each control are both getting notified via OnPropertyChanged. If both properties aren't getting notified this would be your issue regardless if they share the same datacontext (viewmodel).
Blessings,
Jeff
Beware of UserControls by default they bind one way you have to specify TwoWay:
<Binding Mode="TwoWay" ...>
...
</Binding>
Do you see any binding errors in the Output window? If so you can post that and maybe we can understand.
If not try to put a dummy converter in the binding and see if its methods are hit.
One from the multiple issues could be binding source address is changed.
Without seeing the code, we only guess:
Check that the property names in the bindings are an exact match (including case). It is quite common to have typing errors that cause bindings to fail (silently).
in my scenario I have a Linq2SQL Data backend.
my Dataobjects implement IDataErrorInfo to catch errors like Name==null (fast to execute Validationrules that only require the value, nothing special so far )
the Dataobjects are organized in a tree-structure, so each has a Parent and Children
How can I validate if a chosen Name is Unique under the Children of a Dataobjects' Parent?
The problem I'm facing is, that the unique Name validation requires a Database roundtrip which lags typing if UpdateSourceTrigger="PropertyChanged" on the TextBox binding to the Name.
On the other hand, I could set UpdateSourceTrigger="LostFocus", but the problem with that is, that I enable/disable a "Save" button on valid/invalid data. Now in the invalid state you can't click the Save button, so there's no way the Textbox could lose Focus to update (only tabbing away which is ugly, but there are more "unusabilities" with LostFocus (e.g. Error keeps displaying while typing and thus changing the name).
what would be ideal was a way to say for individual validationrules to apply on different events like so:
<TextBox Grid.Column="1">
<TextBox.Text>
<Binding Path="Foldername">
<Binding.ValidationRules>
<wpfresources:UniqueChildValidationRule ValidationStep="UpdatedValue" **UpdateSourceTrigger="LostFocus"**>
... stuff here ...
</wpfresources:UniqueChildValidationRule>
<DataErrorValidationRule **UpdateSourceTrigger="PropertyChanged"**/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
What is the best way to solve this?
EDIT
This MSDN article seems to suggest, that a BindingGroup would be the way to go. I'll look into that...
I finally figured a way to accomplish what I wanted.
The use of BindingGroup worked, but I stripped my solution down because what I needed essentially was a way to show a Validationerror in the correct Textbox.
I did so now with an attached property that I read out on execution of the "save"-functionality. then I manually validate and set a ValidationError on the textbox. that way the textbox can keep its PropertyChanged UpdateSourceTrigger and the lengthy validation is done on submit.
For what it's worth, validation that requires potentially arbitrary time (talking to a database over a network, e.g.) is one form of validation that does not need to be reflected in the UI in realtime. If you can work it so that it is (pre-caching the values that will be checked by reading them from the DB before you need them, e.g.), so much the better, but this is the one scenario where reporting an error after the user has submitted the data is generally acceptable as long as you don't destroy the information that the user entered.
I'm working on a set of controls that has a number of DependencyProperties. The properties are themselves DependencyObjects and created during the get method of the properties. During the Get method, they are also set back to the propertybag using the SetValue() method, so they are in fact valid in Xaml and their properties can be storyboarded without having to explicitly created in the the visual tree.
These DependencyObjects has all its properties as DependencyProperties as well, for supporting DataBinding. They are as mentioned above possible to use in Storyboards.
At the same time I'm developing special designtime support for Blend 3 for these properties and have created an InlineEditorTemplate in the form of a Control. I create the template and set it for the PropertyValueEditor like this:
var vectorEditControl = new FrameworkElementFactory(typeof (VectorEditorControl));
var dataTemplate = new DataTemplate {VisualTree = vectorEditControl};
InlineEditorTemplate = dataTemplate;
In the Control I have the following:
<Grid DataContext="{Binding Value}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=X, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Y, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Z, Mode=TwoWay}"/>
</StackPanel>
</Grid>
The editor shows up and I can edit the data. And even while debugging, I see that it actually sets the data back to the DependencyProperties on the DependencyObjects, but nothing happens to the Xaml. So the data is actually not persisted in any way in the Xaml and lost when I close the Xaml file and open it again.
Is there anything I need to do specifically for it to actually get into the Xaml? I was under the impression that this would happen automatically?
Excellent Question!
The core issue you're running into a misunderstanding as to what PropertyEditors in Blend/Cider end up databinding to.
Consider this object graph:
- MyControl
-- MyControl.MyProperty
--- FooClass
---- FooClass.BarProperty
Let's look at a scenario where we have a PropertyEditor (of any type: Inline, Dialog or Extended) to property MyControl.MyProperty.
When inside MyPropertyPropertyEditor you'd expect to get a fully settable copy of FooClass and be able to manipulate it's members.
That's a good assumption, but the wrong one.
The core issue is that Blend/Cider have elaborate data structures that represent your model at design time. There's about 3-5 levels of abstraction in how Blend/Cider interact with an actual control.
Creating those levels of abstraction allows Expression Blend / Visual Studio designers to be leveraged between framewroks (Silverlight / WPF) and support advanced scenarios (like Property transactions and property chaining).
So, the value you actually get to DataBind to is just one of those levels of abstraction.
Don't believe me? In your custom PropertyEditor, register for this.DataContextChanged event and checkout the type in this.DataContext. You'll end up getting the PropertyValue class (or one of it's friends).
Every single property change you want persisted to XAML (and shown on the design surface) should go through those abstraction layers.
the question you have to ask yourself is "Where do I get one of these absteaction classes for my PropertyValue.Value property instance?".
Well, what I'd do if I were you is create a ModelItem around MyControl.MyProperty and set that as your PropertyEditor.DataContext.
We've shipped an example of using ModelFactory.CreateItem in the Silverlight Toolkit as part of the Chart DefaultInitializer: Source Code, Ning Zhang (Awesome Design Time Dev) explains about ModelItem
If you've got follow-up questions I'd consider pinging PeteBl or UnniR through the Silverlight Insiders mailing list.
Sincerely,
-- Justin
It partly solves my problem. I'm having a dialog with UnniR for a followup.
I couldn't see how I could use this together with the PropertyValueEditor, but for default values this is brilliant and something I'll implement ASAP.
Thanks.
I'm starting to use Binding in my WPF project and I'm actually confused about few things on the presentation side (XAML).
So I want to populate a TreeView with a List of Categories. I know how to write the right HierarchicalDataTemplate for my List of Category instances.
<HierarchicalDataTemplate ItemsSource="{Binding Path=ChildrenCategories}" DataType="{x:Type src:Category}">
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</HierarchicalDataTemplate>
But what now I don't know is from where to get the list. I have here 2 solutions :
I got a Library Singleton class
which return me the right
arborescence, then I need to use an
ObjectDataProvider in my xaml which
would call the
Library.Instance.Categories method. (Which means that the controller has to be completely separated from the UI).
I got a Property ListCategories
in my page interactionLogic
(OpenUnit.xaml.cs), and bind the
tree with it.
I'm not sure about the purpose of the xaml.cs files, what are they made for? Is it normally used to store the properties (and act as a controller) or simply to have a back-end for the UI (for example get values from the UI?)?
In case the xaml.cs file is used as a controller, how do I bind my data to it, I've tried many solutions without success,my only success was with the use of static binding.
I would appreciate any comment or recommandation about UI and Logic Binding in WPF, hopefully I will get less confused.
Thanks in advance,
Boris
After reading this great article, I got a little bit less confused :
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
The article is about the Model View ViewController pattern, and how WPF integrates it. So it seems that xaml.cs files should be used as the ViewController here, and should hold the properties.
It actually make sense since it's not a good practice to mix the View and the Data, we want the designers should have a completely independant work to do.
Also for the solution 2) it is possible if you set the data context to the current file.
I am currently stuck at a dead end with the following situation:
I have a List<Category> collection with each Category containing an Id, Name and a List<string[]> property called Subcategory (where array contains the Name and Id of that subcagtegory - I didn't feel like creating another class).
I have a TreeView with HierarchicalDataTemplate bound properly to categories and subcategories. I also have check boxes next to the tree node and I bind IsChecked to a MultiBinding of the Id of the sub/category and the an overall list of sub/categories that should be checked-off.
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource IsCategoryChecked}">
<Binding Path="Id"/>
<Binding Path="myDataSet.Tables[Categories]/cat_subcat"/>
</MultiBinding>
</CheckBox.IsChecked>
The converter I use simply checks if the name of the sub/category I provide is part of the list (both are values I'm binding to). This works fine and overall I am quite happy with the result.
The problem comes with converting the check/uncheck back. When user changes the IsChecked value I must either add the Id of the sub/category to the list of all checked-off categories or remove that Id from it. Unfortunately when I've attempted to implement the ConvertBack() method for IMultiValueConverter, I only have access to the ACTUAL value that changed (the true or false value of IsChecked) and have NO access to the Id of the sub/category that THAT SPECIFIC CHECKBOX is bound to.
SOLUTIONS I'VE TRIED but failed miserably:
Saving the sub/category name when I do the initial conversion is not an option since I'm using the same Converter for ALL the sub/categories and thus I'd only save the last sub/category I've tried to convert.
Using a MouseUp/KeyUp event is useless because (for whatever reason) they fail to be triggered (a bug?).
I am contemplating to ignore the ConvertBack() and use Checked/Unchecked events instead but feel like that is a rather "dirty" solution because I might just as well ignore the bindings altogether! Is this the only way to go? I've ran out of options but still hope for a "good" solution, if it's out there!
You have a couple of options, and I've used both in production:
Overload Checked/Unchecked, as you've said, which gives you the most control over the situation
Add an IsCategoryChecked property to your strongly typed table in the code behind which handles the changes required behind the scenes, and you bind to the IsCategoryChecked property rather than using the converter
The second one works fairly well thanks to the partial classing with strongly typed datasets. However, it still isn't "seamless".