Is there a way to get WPF to automatically apply a Converter to all bindings of a specific type?
I've seen this question, but it covers a different case (localisation) and thus has no satisfying answers.
My problem: I've got model classes containing Commands, which I would like to bind to WPF Commands. Since the model classes are toolkit-independent, I cannot implement WPF's ICommand there. Instead I have a CommandConverter which wraps CommandModels into WPF ICommands:
<Button Command="{Binding MyCommand, Converter={StaticResource CommandConverter}}" />
This works quite well, except that it is easy to forget about the Converter= and WPF doesn't give any indication that the binding failed.
My question is now: Is there a possibility to force WPF to always a apply a converter to specific types of bindings? Or, alternatively, how can I get WPF to give me proper errors when a Command binding fails?
I don't think you can without either sub-classing Button (you probably don't want to do this), or defining your own attached property and using a TypeConverter attribute on it.
If you want to go with using a default converter via the TypeConverter attribute on a new attached property, you can look at Rob Relyea's informative post here, or MSDN here.
While I've never done it, would it be possible to define a custom Markup Extension? That should cause the value to be sent to your class that implements the Markup Extension, and then from there you can return an ICommand that the Command property is expecting.
As I said, I've never created one my self, but a Google Search seems to bring up a few articles on how to do it.
Check the debug output window. Normally you get to see the binding errors there.
Related
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.
I have an application that is using XAML and C# (MVVM) to create a interface that allows you to start and stop a camera feed.
What I would like to do is to switch between a OFF and ON image depending on the variable IsOn.
I know how to set the image in the UI Manually,
<Image Source="/MyApp.WpfUI;component/Resources/Images/Webcasting.png" />
but I am not sure how to best change the image dynamically based on conditions. I have considered IF statements, but am not sure how to go about that.
Does anyone have any advice or ideas?
One answer would be:
Binding the IsEnabled attribute of your control that displays the stream to a property in your code that returns a boolean.
In your View:
<Image IsEnabled={Binding IsOn} Source="/MyApp.WpfUI;component/Resources/Images/Webcasting.png" />
In this property's getter, put your conditional statements to determine whether or not to return a true or false.
In your ViewModel:
public bool IsOn
{
get
{
if(<some condition>)
return true;
else
return false;
}
}
Notes:
Don't forget to use your implementation of INotifyPropertyChanged to alert the UI when necessary.
If you implement a setter, you could have a button on the View that would toggle the value giving you manual control.
Binding can be used to alter the Source of the stream as well using the same technique as above. I.e., the getter would return the path to the video stream or the path to a static image that says "Video Off". However, this is dependent on whether or not the control you're using can handle that. Instead of the IsEnabled attribute, you would use binding with the Source attribute.
Here a couple links that will show you some similar implementations of this:
High Overview of WPF (MVVM) w/Binding
Simple Binding Example
Good luck.
You have two options here. You can either perform this manually using an if statement as you mentioned in your question, or you can create a DataTrigger & assign it to your control's ControlTemplate.
DataTriggers allow you to set property values when the value of a particular data object matches certain conditions you specify in the XAML. I'd recomend reading the MSDN documentation on DataTriggers for some basic examples of how these work.
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 :)
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
I'm trying to get the Infragistics TabGroupPane to integrate with Caliburn.Micro as per the standard WPF TabControl.
I've tried adding a new convention in the bootstrapper (a modification of the standard WPF one) but have not had any success.
My TabGroupPane is defined as:
<igDock:TabGroupPane x:Name="Items"/>
When an item is added to the collection an exception is thrown "InvalidOperationException: A TabGroupPane can only contain 'ContentPane' and 'ContentPanePlaceholder' instances".
Also, if my TabGroupPane is inside a DockManager:
<igDock:XamDockManager>
<igDock:DocumentContentHost>
<igDock:SplitPane>
<igDock:TabGroupPane x:Name="Items" />
</igDock:SplitPane>
</igDock:DocumentContentHost>
</igDock:XamDockManager>
It doesn't appear to be found by Caliburn at all.
Has anyone else done this before?
Cheers!
Update
I have created my own dock manager class, a blog post explaining it or just the code on bitbucket. Hopefully this will be useful to someone!
If you can't get the ContentPaneFactory suggested in Infragistics blog to fill the TabGroupPane through binding, you might consider these alternative approaches:
keep your VM with BindableCollection in place, subscribe VM change notification in code-behind and change the TabGroupPane programmatically according to the actual change occurred in observed collection
build a custom IResult and invoke it from VM (using Coroutine.Execute) according to the desired TabGroupPane variation.
In IResult.Execute body you have access to ActionExecutionContext.View, so you can reach the TabGroupPane by name and operate whathever action you need on it.
This way you keep your VM free from direct reference to the particular UI control library.
define an interface abstracting the whole Docking Manager, and use it as a service from VM (see this post about the implementation of a Docking Manager). This approach diverges quite a lot from the MVVM idea, but unfortunately most docking library are not very MVVM friendly...
You can add bespoke controls to the ConventionManager class in Caliburn Micro, I would simply follow the example of the standard TabGroupPanel.
I would be wary of amending the actual class though, If I remember rightly (there is a recent post on the discussion forums at CaliburnMicro Codeplex page) You can also add bespoke conventions to the bootstrapper by overriding the Config method? I say this because if you amend the class itself, you will tie yourself to a particular version of Caliburn.
Its a really simple framework and easy to get to know intimately, I would recommend stepping through the code thats run when you bind a view to a viewmodel, there you will learn how these conventions are setup.
Have you tried using a more explicit binding? Caliburn can only do automatic binding on certain elementtypes, and I guess Infragistics TabGroupPane is not one of them!
I guess you have to use something like this:
<igDock:TabGroupPane x:Name="Items" ItemSource={Binding <what to bind to>}/>
Note: This is just used as an example, not sure if ItemSource is the correct property!