Bind TextBox to large string in WPF using MVVM - wpf

I am having a performance problem binding a large string to a a TextBox in WPF.
In the view I am binding a TextBox's Text property to the view model's Output property which is a StringBuilder.
View:
<TextBox Text="{Binding Output, Mode=OneWay}" IsReadOnly="True"/>
ViewModel:
public StringBuilder Output
{
get { return _output; }
}
As the text in the StringBuilder gets larger the performance of the binding degrades.
What's a better way to do this using MVVM?

One possible way of getting around delays in databinding is to use asynchrnous binding. You can do this by setting IsAsync property of your binding object :
This will of course not solve the problem of the binding taking a long time but will stop the UI from freezing whilst it does the binding.
You can also use priority binding to show a cut down version of the text (which is quick to load) whilst the larger text item is loaded. Priority binding is described on msdn - >http://msdn.microsoft.com/en-us/library/ms753174.aspx.

I can't really imagine why the performance of the binding would be slow because it is simply displaying what's in the StringBuilder. However, the first thing that comes to my mind is how you're adding to the StringBuilder. Appending, removing, replacing, or inserting characters into the StringBuilder may be what's giving you performance issues.
I don't really know what kind of string you're building or what the requirements are, but you may need to use a different structure.

Related

Q: Update viewmodel property from a listview binded textbox

i've got a textbox which text is binded to a listview selecteditem as follows:
<TextBox x:Name="txtAdditional" Width="300" Text="{Binding ElementName=lstPersons, Path=SelectedItem.Additional, Mode=OneWay}" />
Now i like to implement a mechanism to add new items to the listview using this textbox to get the actual data. So i would like to bind the text of the textbox to a property of the viewmodel so it can be processed by a command.
So it the textboxes text has to be binded to the listviews selecteditem and additionally to a property of my viewmodel.
I've searched around and found some approaches but i can't help to think that there should be some simpler mechanism to archive this goal.
What I found by now:
Using MultiBindung with some kind of ValueConverter? So it seems to me that this is primary for displaying and not for updating a viewmodels property.
The use of some selfdefined custom control?
The use of an BindingProxy with in- and out-dependencyproperties like in Impossible WPF Part 1: Binding Properties?
Is there another, simpler solution to this or would i have to use one of those above?
And if one should use one of those approaches, which one whould you choose?
I can't help but thinking that this issue hasn't been given some thoughts already, using an mvvm pattern?! ;-)
yes thanks to the hint from BionicCode.
We, or better I should have to think the MVVM concept out. Of course no - or at least as little code behind as possible.
I added the property "selectedPerson" to my viewmodel and bound the SelectedItem of the listview to this property. So the object related properties were at hand directly through the "selected" object in my viewmodel and there was no need anymore to access the textbox content at all.
Thanks to BionicCode for the hint!

wpf binding a TreeView to a SortedDictionary<string, List<Class>>

OK, once again, my Google-Fu isn't up to par and I would really appreciate a little guidance here.
I have a WPF app with multiple pages, one of which contains a TabControl, of which one of the tabs contains a grid, in which one of the columns contains a StackPanel with just two items on it: a Label and a TreeView. I have no need to update the TreeView once the content is obtained. The app uses MVVMLight (great toolkit!) to expose the data and said data is exposed in an mvvm (observable) property as it should be. I have checked and the data itself is available in correct form once I get to the point of setting the ItemsSource property so I know it's not the lack of data or the structure of the data itself. I have looked at all the entries on the web (at least the first 4 pages worth) matching the search terms "wpf treeview dictionary" and all articles come close, but don't get me to where I need to be. I'm missing something and what's worse, IntelliSense is even "helping" by providing the correct values for the xaml settings. So I know I'm close, but after two days of frustration, I'm throwing in the towel and asking for an assist.
So...to the meat of the problem: The data that the TreeView needs to display is in the form of SortedDictionary<string, List<ServerEntityNameMsSqlSvr>>. A ServerEntityNameMsSqlSvr class contains multiple properties, one of which is FullName. What I want the TreeView to display is the dictionary Key as the parent node and the FullName from each of the items in the List<ServerEntityNameMsSqlSvr>. You'd think that'd be simple, no? Not for me, the closest I can get is to display the Key of the dictionary, but either nothing for the children (best case) or throw an exception that stops the app with a null exception (worst case).
Here is the xaml I'm using (worst case):
<TreeView Grid.Column="0" ItemsSource="{Binding TableHierarchy}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Value}">
<TextBlock Text="{Binding Path=Key}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="awe:ServerEntityNameMsSqlSvr">
<TextBlock Text="{Binding FullName}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
"TableHierarchy" is the MVVM property that exposes the data, it is declared as SortedDictionary<string, List<ServerEntityNameMsSqlSvr>>. The DataType "awe:ServerEntityNameMsSqlSvr" is a simple class with a few methods and properties, nothing special. One layer of inheritance, no interfaces. Of the properties that are available, I want to expose just the FullName, which is declared as public string FullName => _FullName(); Yep, it calls an overloaded method to build the full name but the result is a simple string (and the method call happens when the data is built, not a display time, iow, the values are already there, at least debugging to the setter shows that the content is correct.
Some of the solutions that I have researched suggest that the data type be changed to something other than a dictionary. In this case, that's not possible and given that the lists are, on occasion, quite large, I don't want to rebuild it into something else. This needs to work with the sorted dictionary as declared.
The xaml shown above is indeed correct, however, the gadget that supports the data (the methods in the ServerEntityNameMsSqlServer class) all need to not throw exceptions under any circumstances. In this case, one of the methods not directly involved with the author's code but used somewhere else in the framework (an overloaded call to "Equals" that was constructed to check individual property equality to determine the result) was throwing a null exception because a property wasn't filled in for the particular use case.
Difficult to find, but that was the cause.

Two way Multiconverter or Converter with property

I need to convert a two part value into a string and back again for example:
{Value = 12.0, Units = DimensionUnits.Inches}
Converts to
"12 in"
This is pretty simple using a multivalue converter to convert from source but becomes impossible to convert back if the user doesn't provide the unit type in the string so a Multivalue converter doesn't look like the solution I need.
A direct converter parameter won't work because the unit type needs to be bound so I researched how to create a bindable parameter. Creating a bindable parameter is actually pretty easy - deriving from DependencyObject - but then you have the problem of your converter not living in the visual tree - and thus not being able to bind to anything - to which there are 2 solutions:
http://tomlev2.wordpress.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
http://shujaatsiddiqi.blogspot.com/2011/02/wpf-binding-converter-parameter.html
The first method derives your Converter from Freezable instead of DependencyObject to allow DependencyProperties. This works and allows you to bind within the Whatever.Resources section but it has extremely odd behavior like only listening to the binding the first time it is used in your entire application.
The second method doesn't seem to work at all. The dependency property is never updated when the source changes.
<pf:BindingReflector Target="{Binding Source={StaticResource DistanceConverter}, Path=Units, Mode=TwoWay}"
Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=g:TestWindow, AncestorLevel=1}, Path=Units, Mode=TwoWay}"/>
Does anyone know of a solution to this problem or is this a big limitation of WPF?
Personally, I would actually suggest rethinking this a bit, and doing either:
Keep the final string one-way using a IMultiValueConverter, and have this be input as two separate items. This seems like a reasonable approach, as the units appear to be an enum with a specific set of options. A combo box for units and textbox for amount seems appropriate, and the total display can be done with a one-way converter.
Handle this conversion explicitly in the ViewModel. This has the advantage of allowing much better validation handling, which is probably going to be required as entering two separate values (amount + units) in one control is likely to not validate correctly. By moving the logic directly into your ViewModel instead of binding to the properties, you can correctly handle errors in a clean way.

How to data bind the text property of a TextBlock to the text property of a TextBox

I have a WPF application with two pages. On page one, there is a TextBox (boxSource). On page two, I have a TextBlock (blockDestination). I want to databind in XAML, the Text property of boxSource to the Text property of blockDestination.
I set the DataContext of page two to page one when the application is initialized. I setup blockDestination as follows:
<TextBlock Name="blockDestination" Grid.Row="0" Grid.Column="1" Text="{Binding boxSource, Path=Text, Mode=OneWay}" />
This does not pickup the value of the TextBox. My guess is that it is because the TextBox is a variable instead of a property?
Can anyone explain the issue, and is there an elegant solution?
Thanks for any help
For that XAML to work, your "page one" will need to be set as the data context of page two, with the boxSource variable defined as a property, so that in the setter, you can raise the PropertyChanged event.
Matthias is right, though, this is a pretty brittle way to implement this, and one of the places where an MVVM approach will be more robust in the long run.
An elegant solution would be to define a View Model common to all pages. You should always bind to properties of the view model and should avoid binding to UI Elements. Using a view model you can always access all neccessary values and define several presentations in different pages.
I've read something about pages having their own object space, so that UI elements can have the same name in different pages. Also it can happen that the first page isn't available after loading the second one. The binding target would then be unavailable.

How to postpone an update to a Binding in WPF

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

Resources