Swapping data binding in code - c#

I have two data-bound text boxes. One is bound to a string and the other to a number. The 'default' binding is set in XAML. Under some circumstances I need to reverse the bindings at runtime (the string is usually a prefix but sometimes it's a suffix).
I have the following code in my view model, called when the window is loaded:
Binding stringBinding = BindingOperations.GetBinding(view.seqLeft, TextBox.TextProperty);
Binding numberBinding = BindingOperations.GetBinding(view.seqRight, TextBox.TextProperty);
view.seqLeft.SetBinding(TextBlock.TextProperty, numberBinding);
view.seqRight.SetBinding(TextBlock.TextProperty, stringBinding);
After that the code loads the properties to which the binding refers.
The problem is that the 'new' binding doesn't seem to work. What have I missed? Is there a better way?

I might consider exposing Prefix and Suffix strings to which View can bind, then use logic within the ViewModel, or whatever backing object you're using, to fill those strings accordingly. This option neatly segments the business concern from the visual and simplifies what you have to keep track of in your view.

Why monkey around with the bindings at all? If you want to have a TextBox that's bound to one of two different things, create two TextBoxes, put them in the same location, and toggle their visibility based on whatever your swap condition is.

The only thing wrong with my code was the TextBlock.TextProperty in the SetBinding calls! They should, of course, have been TextBox.TextProperty but I'd messed with it so long I wasn't seeing the wood for the trees.

Related

Using ViewModels in ObservableCollections in Prism

As far as I know, the default way to use a ObservableCollection that is bound to a listview is with model classes as elements (ObservableCollection<MyModel>). So when a listview element is selected, we use NavigateAsync and pass the model, which then can be used by the ViewModel to "fill itself".
The problem with this approach is, that it's not possible to use ViewModel properties for binding in the listview.
For example:
I have a View, ViewModel and Model "PickList", which contains a collection of "PickLine" objects - each having a View, ViewModel and Model themselves. The PickLine object contains a property "PickedQuantity" and a property "OpenQuantity". Now in my PickList view, I don't want to bind these two to separate items (e.g. two labels), but I want to have one label to display both I a format like for example "PickedQuantity / OpenQuantity". I know this example can be solved by using multi binding or something like this. But that's not the meaning of it all.
My PickLine ViewModel already has a property "QuantityString", that I want to bind to the label of a listview element via DataTemplate. But how can I do this. Is it even possible?
Make a property that combines the two other properties and bind to that. E.g.:
public string FullQuantity {get {return $"{PickedQuantity} / {OpenQuantity}";}}
Then in the setter for PickedQuantity and OpenQuantity, you will want to call whatever PropertyChanged method you have set up to notify the bindings of a property change and pass in the FullQuantity property name so elements that are bound to FullQuantity get updated when either PickedQuantity or OpenQuantity are changed.
This way, you are only binding one label's text to one property and that label would get updated when either of the two quantity properties are changed.
Note: I am unfamiliar with Prism, but this approach should work regardless of the Mvvm framework in use.
Your PickListViewModel should expose a collection property whose items are of type PickLineViewModel (not PickLine).
Whether you need an ObservableCollection<PickLineViewModel> depends on where changes can happen - in service / model that initially created the PickLines or in the GUI or both. In any way, you have to make sure the changes are propagated from one side (the collection of view models) to the other (the collection of models). Google wrapping observable collection as a starter (hint: avoid two-way sync if possible). These blog posts are old but still relevant and make a good reading. A trivial wrapping is described in this answer.

Binding to a property by variable name (ideally from xaml)

I'm trying to databind (ideally from XAML as i know how to do this in code behind but it would be far from trivial to traverse my heavily templated tree just for that) to a property who's name i only know at runtime
What i would like to do is not the usual:
Content="{Binding TheProperty}"
But something like
Content="{Binding PropertyName=TheNameIsStoredInThisProperty}"
I'm trying to do this because i generate the UI from templates when binding to my plugins, but the UI is specified in a set of POCO and separate from the ViewModel, so i want to be able to generate my UI and still be able to wire it to the correct properties on the ViewModel, any advice is most welcome.
The immediate solution might be to bind to an arbitrary property in your VM with an IValueConverter that goes both ways, and the ConverterParameter is the string containing the source property name. Once inside the value converter you can use an interception pattern to Reflect out the value you need from the POCO. You can then pass the value up to the source property in the VM. Rather like a pipeline :) This will work but still leaves you with being notified when the POCO changes.
A Markup Extension seems plausible but likely to be brittle and provide naught in the way of performance improvement.
An Attached Behaviour still leaves you with having to Reflect and does not easily solve the problem of notifications originating in the POCO (AFAIK only Unity knows how to do that).

Why ever use a multi binding converter?

Couldn't I just use a single binding converter and as a parameter pass in the DataContext and from there pick what properties I want to use?
If you pass the whole object instead of the individual properties, then the binding expression will not be re-evaluated when the individual properties change. You will be losing the benefit of the INotifyPropertyChanged mechanism.
You might want to be more explicit and take in the minimum extra information (which is just generally good programming practice), or you may want information from more than one source - e.g. Your value might be dependent on a property of the datacontext and the checked state of a checkbox somewhere else in the view.
You can do that, but the binding will not update if the relevant properties change that way. Besides the updates Multibinding is needed for more complex bindings to different controls and data-objects.

Correct way to use a DataGrid when utilizing a LINQ2SQL DataContext table as its ItemsSource (best practices)

So, I am learning Linq2SQL by building a simple UI. I am using two DataGrids to display a master/details type interface, where "Customers" are displayed in one grid and, when selected, some details displayed in the other grid (for example, records from a foreign key table such as "Orders", whatever).
Now, every example I have read regarding the use of a DataGrid shows something like this:
using( var db = new TestDataContext() )
{
// AutoGenerateColumns set to false and
// column bindings set to certain properties
// of the Customer class.
grid.ItemsSource = db.Customers.ToList();
}
Well, that doesn't work because the DataContext is accessed after this code is executed due to data binding, and of course, the Context object has already been disposed. Ok, that's fine; I can use a single DataContext for all of my grid operations, even though the DataContext class was designed to be used and disposed of quickly. I'm not sure if keeping a single DataContext around is going to bite me in the future yet.
So now I run into the issue of updating the database and reflecting those changes back to the grid(s). The simplest way I have come across is to set ItemsSource to null and then bind it once again to the table. This just feels 'dirty' to me and I have to imagine I am missing something. In theory I could use an ObservableCollection and bind that to the grid, keeping it in sync with the underlying data, but I haven't yet figured out how to get the grid to display data from the observable collection (I bind it in XAML and only empty rows are rendered in the table).
TLDR:
So anyway, my question is this; what patterns do you experienced LINQ2SQL guys use for this type of a scenario? It seems that all of the examples I can find are overly simplistic and don't quite apply in a real world use case (even one as simple as mine). Basically, how do you use your DataContext, how do you keep the grid updated when new items are added to a table, and what are some general best practices here?
In the example code you provided, the datacontext would only be getting accessed again by bindings if you are binding to lazily loaded properties.
Have you looked at the LoadOptions.LoadWith<>() function on the datacontext (assuming it hasn't been renamed since I last looked at linqtosql)
Personally I have no problem taking a hold of the datacontext and keeping it around for the page life, though not a single one for the whole application life.

WPF check if a dataproperty has an binding

Hej,
I'm trying to make som general functionality for my ListView, so that the content of a ListView can be exported to CSV directly.
I'm trying to achive this by getting the datacontext and analysing the ICollectionView for this. From here I have access to the all the objects from via ICollectionView via SourceCollection, in which I (for now) presume sorting/and filtering is respected.
The challange here is that I only want to output the columns that also are showed in the ListView.
When iterating my collection, is there a function where I can evluate if a property in a class (with notification suppoert) has a binding to it?
The esiest solution for now would be just to output all properties, but I'm not interested in this, since oid's are not fun to look at.
Thx in advanced.
/Ian
I suggest you recognize that the ability to determine which data is being displayed is a business requirement. Thus, you should embody this requirement in your model. In other words, your model should clearly indicate which columns are visible - you shouldn't be trying to infer this from your existing properties, nor should you be examining your view.
There are a whole bunch of ways you could do this, but the key is to have this information on hand in your model.
Why don't you just look at the DataTemplate and evaluate it including the binding inside?
There's no easy way to do it... You can check the binding on the target side (dependency property), but not on the source side.
For what you're trying to do, you could loop through the columns of the ListView and check their DisplayMemberBinding, but it could be undefined (the cell content might be defined using the CellTemplate property instead).

Categories