x:Bind in UWP (Universal Windows Platform) - c#

Right. So moving from WPF to UWP, I'm trying to use x:Bind to get compile-time benefits. Simple scenarios work fine; however I have found a number of issues that I was not able to solve. They are all related, so I thought I'd post them in one place:
I haven't been able to make Intellisense work with x:Bind. I have set DataContext (as well as d:DataContext just as we do in WPF) both in XAML and in the constructor, but it won't show members no matter what. Has anyone done this successfully?
Then I read somewhere that in UWP, DataContext is always set to Page's code-behind (really??) and that I need to define a ViewModel type property in the code-behind and then use that property in x:Bind. Is this correct? I tried it and it works but gives rise to the next question.
If I define a property of ViewModel type in Page's code-behind, Any sub-properties that raise PropertyChanged notifications do not update the UI. For example, if the code-behind property is named Game (of type GameVM) and there is a public property in GameVM named Player (of type GamePlayer), and in turn GamePlayer contains a property named Name, the x:Bind path will look like {x:Bind Path=Game.Player.Name}. But if I do this, any change notifications raised from within Name property do not update Page's UI.
One alternate I tried was to listen to PropertyChanged at each level and then bubble it up the hierarchy, but that hasn't worked. Even if it does, doing this seems a bit too much work. In WPF sub-properties like Game.Player.Name work properly without having to doing property change bubbling. Or am I missing something?

Right. After playing with it for a few days and searching numerous references, here are my findings:
{x:Bind} lacks design-time support. The feature is on the wishlist though. You may want to upvote it there.
(The new version of Visual Studio 15.4.4 does support Intellisense in {x:Bind}in the required way.)
{x:Bind} uses code-behind as its DataContext. So you need to define a public property of your ViewModel type in the code-behind and then use it in your {x:Bind} path.
As pointed out by IInspectable, the default mode for {x:Bind} is OneTime, unlike {Binding} which uses OneWay or TwoWay in almost all cases. So you need to explicitly specify Mode in your binding. People coming from WPF should take special care of it.
Sub-properties that implement notification change work perfectly fine in {x:Bind}. There is no need of bubbling these notifications upwards in the property hierarchy. The problem I was facing (#3 in the question) was because my sub-property was of type List<T>. I changed it to ObservableCollection<T> and it started working.
Hope this works somebody down the road.

Well as a beginner, the only question I can answer for you is the first one. Intellisense does not work inside the {x:Bind}. The members are never shown there in UWP for some unknown reasons. As for the next two questions of yours, I am still working on them.

I ran into the same challenge that you have seen. In my experience, in order to create the compile-time binding and have it update with custom objects as properties, the Page class seems to need to know about the data context and custom objects... all you need to do is reference them in the code behind, and then bind to them in the XAML. This creates the code generation objects it needs.
For example, I have a viewmodel, CustomerViewModel that is bound in XAML. That viewmodel also has a property of type IGuest. In order to use the guest object and have it update properly, I came up with this in the code behind...
CustomerViewModel vm
{
get
{
return (CustomerViewModel)DataContext;
}
}
IGuest g
{
get
{
return vm.CurrentGuest;
}
}
public CartGuestControl()
{
this.InitializeComponent();
}
You don't need to assign any of the UI data contexts from the code behind... simply reference the datacontext that is bound in XAML. When binding to any straight viewmodel properties, I use {x:Bind Path=vm.IsEditing, Mode=OneWay}. For binding to any of the guest properties, it looks like this, {x:Bind Path=g.FirstName, Mode=TwoWay}. You could do something like this for your Player object.
I have run into times where x:Bind simply won't do what I expect it to do no matter what I try. This can usually be solved by breaking things out into smaller user controls with more specific data contexts or by using "regular" Binding.

Related

WPF Thread binding access error on binding in MVVM

So I am trying to incorporate dynamic-data-display for WPF into my MVVM caliburn project (I am using the LineChart control from future of dynamic data display, if anyone wishes to test this error). There is a LineChart that binds to an ObservableCollection. It only works if the collection is made in the code-behing of the control which has the LineChart. If you try to bind to a collection the ViewModel the dependency property raises an InvalidOperationException. How can this problem be solved?
I have seen that happen when you change the collection which the property is binded to and know ways to fix that, but never in the actuall proccess of binding. I've tried putting the creation of the collection in a dispatcher invoke (like you wold do with an add or remove) but it didn't help.
Edit: As I stated in the second paragraph the exception is NOT at the point of changing the collection. It is being raised at the point of binding. Even more, I have tried to use the solutions in the other question and they did not help.
Edit #2: The exception message is "The calling thread cannot access this object because a different thread owns it".
People keep telling me solutions to collection changes but it doesn't even get to the changes. It fails at binding stage (ItemsSource="{binding collection}" in xaml).
Edit #3: I double-checked and noticed that the ViewModel is created in the UI thread which only made more questions.
Ok, it took me quite a while to find the root cause of your problem.
Unlike from what others suspected, this isn't a multithreading issue at all.
Instead it's an issue with the DynamicDataDisplay library you are using.
There's a clear reason why your ItemsSource binding works on your ListBox object and doesn't work on Chart (of type Microsoft.Research.DynamicDataDisplay.Markers2.LineChart) :
Chart neither has a visual nor a logical parent.
You can check this if you insert the following code into Button_Click and set a breakpoint after them:
var visualParent = VisualTreeHelper.GetParent(Chart);
var logicalParent1 = Chart.Parent;
var logicalParent2 = LogicalTreeHelper.GetParent(Chart);
You can see that they are all null.
So the Binding that you set on LineChart.ItemsSourceProperty with Path=ExampleCollection cannot find any source value and just assigns null to the ItemsSource. That's because the DataContext is inherited from the parent - but when there isn't any parent then there isn't any DataContext to inherit either.
And because Chart isn't part of the visual or logical tree, there is no (easy) way any binding to an outside DataContext can even work.
To verify that the DataContext is null just add this line to the preceding code:
var dataContext = Chart.DataContext;
Now there are three possible solutions for this.
First, you can manually inherit the DataContext from Window using the following code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Just add the following line.
Chart.DataContext = DataContext;
Chart.StrokeThickness = 3;
Chart.SetBinding(LineChart.ItemsSourceProperty, new Binding("ExampleCollection"));
// ...
}
If you simply add this one line, you'll see that your other multithreaded code is working just fine and the chart is updated with some kind of sine wave pattern.
Second, as another possible solution you can consult the documentation for the DynamicDataDisplay library and check the correct and intended way to assign an ItemsSource to a LineChart using data binding.
I tried searching for documentation myself and even debugged a lot of code from that library for two hours or so, but the documentation is nearly non-existent and the code is far too complex to fully understand it in a few hours. I tried using several tools (Visual Studio Live Visual Tree, Snoop, ...) for displaying the visual tree of the ChartPlotter but I got a StackOverflowException every time, so essentially something in this library is kind of flawed and buggy.
Third, you can use a Resource as a kind of proxy object to create a "binding bridge" to the same instance of the MainWindowViewModel.
For this to work, you have to do something like suggested here: Data binding outside the visual tree. Data Context bridging
Bottom line: So, if you just want to get the job done, I would set the DataContext in code like shown above. (Especially if the instance of the ViewModel in the DataContext never changes.)
If you want to use pure data binding then I would probably use the "binding bridge" or search for another charting library that supports this scenario.
As THIS thread states you can use the UI dispatcher and invoke the function that changes your ObservableCollection on the UI thread. Application.Current.Dispatcher should give you the UI dispatcher. As the solution suggests it can be right in the ViewModel. However, a cleaner and more generic solution is to IMPLEMENT a concurrent and still observable collection it would still store the dispatcher and run the changes on the UI (or specified) thread.

XAML: Under the Hood

Well, i must admit, still sometimes XAML seems a bit mysterious to me. The thing is, i always liked to debug through the C# code (setting lots of breakpoints in them) to get the idea of "what is happening" and "how is it happening". But with declarative XAML syntax that's not an option. I think you'll agree that to work with XAML, or to be precise, to work with/understand some existing XAML code you got to "already know" how things work with XAML declaration. There is just no way you can know/learn things investigating the execution of your application code. So i'm more than interested to take a look through XAML inside-out, as detailed as possible. I'm NOT talking about "learning" XAML, I know the basic stuff. May be i can provide some examples to clarify the sort of things i'm looking for -
Compared to C# code how an object gets instantiated when we use them in XMAL? Are they stored in managed heap? Same way as C# code-instantiated objects?
How the properties get set while using Mark-Up Extension syntax for Data/Command Binding?
When any property of an INotifyPropertyChanged type gets updated, how the Binding instatnce inside the XAML syntax updates the itself? How exactly it gets notified it at the first place, & by whom?
A viewmodel can be set as the DataContext of a view at runtime by defining Typed DataTemplate, like -
<DataTemplate DataType="{x:Type viewmodels:AccountsViewModel}">
<views:Accounts/>
</DataTemplate>
How does it happen actually? What are the rules for setting DataContext other than searching for the DataContext property upward the logical tree?
How the whole template things (DataTemplate, ControlTemplate & ItemsPanelTemplate) are treated/resolved at run time.
etc. etc. etc.
So if you are good/experienced/expert in XAML what would you suggest (links, articles, blogposts, books whatever) as reference that helps getting clear & deeper understanding about how XAML works "under-the-hood"? Thanks in advance.
Most can be explained by don't thinking of XAML as a real programming language, more like a declarative language. Everything you do in xaml, can be made in C# aswell, and in fact this is whats happening.
Compared to C# code how an object gets instantiated when we use them
in XMAL? Are they stored in managed heap? Same way as C#
code-instantiated objects?
Yes because they are just c# objects. Most resources are stored in a hibernated state, i rememberd the word inflated somewhere. Converter or other "direct" c# objects are created when they are needed. Important here is that these resources are usually shared, so they will get created only once.
How the properties get set while using Mark-Up Extension syntax for Data/Command Binding?
This again depends on where you use the markup extension. In a Style? In a Template? In a instanced user control like a window? Usually they are evaluated when you actually need them. It wouldn't make sense to evaluate them, when the inflated style is stored in the actual resource dictionary. They get evaluated when you actually use the style on an object.
When any property of an INotifyPropertyChanged type gets updated, how
the Binding instatnce inside the XAML syntax updates the itself? How
exactly it gets notified it at the first place, & by whom?
By the binding engine. WPF checks if your DataContext inherits the INotifyPropertyChanged interface, attaches to the event provided by the interface and listens to any changes. If such an event is raised, the binding engine will just call the getter again.
How does it happen actually? What are the rules for setting DataContext
other than searching for the DataContext property upward
the logical tree?
In short: None other. Datacontext is simply an inherited attached property. If you don't re set it on a child control, it will take the value the parent has until it reached the root. The only exception to this are ContentControls and ContentPresenter they will not inherit the DataContext but will change them depending on the content. So these controls always have by default the Content as their DataContext.
How the whole template things (DataTemplate, ControlTemplate & ItemsPanelTemplate) are treated/resolved at run time.
Simply spoken: Everytime WPF finds a non ui object, it tries to find a DataTemplate for the given type. In an ItemsControl for example: You can bind a list of MyClass; unless you provide an explicit DataTemplate or DataTemplateSelector it will search the resource tree upwards for an implicit style. Again remember that this already does not happen in XAML, but on the C# objects that was generated out of the xaml.
And is it by any means possible (at present or near future) to debug
through XAML code?
How do you think you can debug something that is not executed, but evaluated on compile time?
Please don't take this as 100% correct. Over the Years this is what i gathered of informations about XAML and the usage. If you have any corrections or find something that is clearly wrong. Please tell me, we are all here to learn and i always learn new things about the stuff i use :)

Find XAML Framework Elements Bounded To An Object

How can I find and access to Elements which are bind to an object in XAML ?
Edit : Let's say I have a EmployeeViewModel which is assigned to EmployeeView's DataContext and a EmployeeModel inside my EmployeeViewModel, I want to know which properties of my model bounded to View's Framework Elements (Controls) also I want to have an access to each control bounded to my model properties.
UPDATE: In light of the question being clarified by SaberAmani in that he is trying to add validation to his models and show a validation summary..see the links below.
http://msdn.microsoft.com/en-us/magazine/ff714593.aspx
http://codeblitz.wordpress.com/2009/05/12/wpf-validation-summary-control/
http://wpfvalidation.codeplex.com/
http://f10andf11.blogspot.co.uk/2012/02/wpf-validation-summary-control.html
For reference for people that want to discover Bindings:
You don't mention if your XAML is in WPF, Silverlight, Metro or Phone7 (thus you may be more restricted in what you can do).
There seem to be a few possible ways to do what you want:
Reflection
MarkupObject / MarkupWriter
TypeDescriptor+DependencyPropertyDescriptor
Custom Binding Markup Extension
Take a look at this link.
http://blog.spencen.com/2008/05/02/how-to-get-a-list-of-bindings-in-wpf.aspx
He uses reflection and suggests this is the classical way to do it...but also mentions MarkupWriter as another possibility. NOTE: the reflection method doesn't discover Attached Properties which may have bindings.
Here are some links that use MarkupWriter...this would allow you to discover the attached properties.
http://www.codeproject.com/Articles/21139/An-XAML-Serializer-Preserving-Bindings
http://blogs.msdn.com/b/marlat/archive/2009/05/24/getbindingexpression-a-good-way-to-iterate-over-all-dependency-properties-in-visual-tree-in-silverlight-3.aspx
Related links:
Retrieve all Data Bindings from WPF Window
Getting list of all dependency/attached properties of an Object
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/580234cb-e870-4af1-9a91-3e3ba118c89c
you could use reflection to loop through properties and use FrameworkElement.GetBindingExpression on each property to build, for a given Framework element, all its bindings.
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.getbindingexpression

How to forbid automatic databinding on validation error

I'm creating a simple database application in C# WPF using MVVM as Relay Commands and databinding. For in-memory storage of database content I use ObservableCollection, which is binded to the Datagrid as follows:
<DataGrid ItemsSource="{Binding Path=Softwares, Mode=OneWay}" SelectedItem="{Binding Path=SoftwareSelection, Mode=TwoWay}">
when the item is selected user can chose to edit it. For editation a form is opened with a bunch of textboxes with the data of given entity. All the fields are validated using IDataErrorInfo, unless all textboxes are valid, the ok button is not enabled, and therefore no changes can be saved to the collection and to the database.
Here is how the example textbox looks like:
<TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
But the tricky part is, in case I change some values in textboxes and then close the window, the new values are propagated to the ObservableCollection, which I don't want to. Do you have any idea, how to prevent such behaviour? I would like the databinding work only after clicking the button. Otherwise the databindng works well, so as the button (dis/en)abling and reflecting changes to the database and to the collection after clicking. Both views are serviced by different ViewModels, data between views are passed by firing events.
I tried to add to the DataGrid UpdateSourceTrigger=Explicit to the ItemsSource binding, but didn't help. Perhaps, I'm missing some application logic?
Thank you very much for your help.
This is where most WPF developers make mistakes of assumptions!
In MVVM dirty data can be stored in the ViewModel and that's what the layer of VM is for! It mimics the View from Model's perspective and because View is in error, the ViewModel would also be in the error. Thats perfectly valid.
So having said that, the question remains
How will you NOT allow the temporary / dirty data to flow to your
ObservableCollection?
Two ways...
If your ObservableCollection is specific to your model class (say MyItem) then if your Model class (MyItem) is an Entity class \ DAL class \ NHibernate class create a wrapper of MyItem class called ViewModelMyItem and then instead of ObservableCollection<MyItem> use ObservableCollection<ViewModelMyItem>.
This way dirty data from your View would be inside ViewModelMyItem and it can only be legitimately flown back to your model class (MyItem) ONLY when Save button is clicked. So that means in Save Command's Execute() delegate you can copy \ clone the ViewModelMyItem's properties into Item's properties, if validations in ViewModelMyItem are fine.
So if Item is an EntityType class / NHibernate class / WCF client model class, it would always only valid data as ViewModelMyItem is filtering the temporary / dirty information upfront.
You could use Explicit binding model. It stops the TwoWay data to flow back to the sorce Item unless BindingExpressions.UpdateSource() is explicitly called.
But according to me, this defeats MVVM in straightforward way because ViewModel will not have what UI is showing! Still however you can use *Attached Behavior * to govern explicit binding by staying in MVVM space!
Let me know if this helps!
You're better off putting the code into the domain object's property setter. Then synchronize with the visuals by triggering the NotifyPropertyChanged handler.
More on this topic:
http://msdn.microsoft.com/en-us/library/ms743695.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
Setting the Binding Mode to Explicit should require you to call the binding expressions UpdateSource() method to send changes back to your model. Because you only mentioned that you set Explicit on the DataGrid's binding, I'm guessing you only need to make sure that you have that mode explicitly set on any property that is being bound directly back to your model. Such as your TextBox's Text Binding, in the case above. That will likely fix your problem but require you to call UpdateSource() on each target's BindingExpression one way or another.
If you're using one of the mainstream ORM's (EF, Linq to SQL, etc), then chances are your Entities automatically implement INotifyPropertyChanged and INotifyPropertyChanging. Because you are sharing a reference to your single instance, all changes in your edit will be reflected in your main view and anything else Binding to that instance. As a dirtier alternative, you can just create a separate instance of the same type and manually copy the values back over when the window's dialog result is true.
The first approach requires you to manually update the bindings, the second approach requires you to manually update the values from the Edit's instance.
With some more code, I can help with your specific approach.

Binding to Entity Object in WPF (C#)

I have a TextBox bound to the Entity Framework object User. Works fine. But now, when I change the User object to the new User.CreateUser(0, ...) or null, TextBox doesn't change.
Why?
Best regards, James
pls post your binding and your datacontext, otherwise its hard to say whats wrong. i could just assume that INotifyPropertyChanged is not implemented.
You have to make sure that the binding hooks in at right level, not all changes are observed by the binding engine, e.g. if you only specify the Source that is identical to assigning the object referenced by the source, the binding will look for the PropertyChanged event on the source to update itself if you bind to a property using the Path, however it will never know if the source is swapped out.
If you bind to the User using the path this is not your issue, just what exactly is wrong is not inferable (for me, that is) from your question alone, you should probably post some code.

Categories

Resources