Unable to bind to DataContext - c#

I am having a really weird problem. I am trying to bind a property to the DataContext but it is not working. This is what I am doing (in the Window.Resources section):
<myNS:MyClass x:Key="myObj" MyProp="{Binding}"/>
Elsewhere in the code, I set the data context like this:
myWindow.DataContext = MyNameSpace.MySingleton.Instance;
I didn't get any errors, but the binding didn't happen. So I added a Debug converter to see if I could figure out what was going on:
<myNS:MyClass x:Key="myObj" MyProp="{Binding Converter={StaticResource Debug}}"/>
I set a breakpoint in the converter and the value being passed was null. Figuring that things were out of order, I set a breakpoint on the line that sets the DataContext. It was hit first, then the breakpoint in the converter. So the DataContext is being set before the binding occurs.
Finally, to try to get something to work, I changed to this:
<myNS:MyClass x:Key="myObj" MyProp="{Binding Source={x:Static myNS:MySingleton.Instance}}"/>
That worked.
I really don't like spreading out the bindings like this. I would rather just bind to the DataContext. The window in question contains many bindings to properties on the DataContext and these all work fine.
Can anyone explain what I am doing wrong here?
JAB

Resources, as well as some other elements like Context Menus are not part of the visual tree.
Thus, they have no governing FrameworkElement to get a data context from. Usually, a standard class won't take advantage of the binding syntax, as it requires deriving from DependencyObject, but if you do end up needing a binding in a resource (say, for a converter) you can use this trick:
Set your root element to have x:Name="Root"
Use your bindings like this:
MyProp="{Binding Source={x:Reference Root}, Path=DataContext.<YourProp>
This binds using the root framework element as the "starting point" and you can get to the data context normally.

What an idiot I am!
I started to respond to #BradleyDotNET (thanks for the response, by the way. It is what helped me solve the problem), and figured out the solution. My class DOES derive from FrameworkElement. I did that because I needed to make use of data binding, even though it has no visible component.
I posted another question dealing with how to instantiate an object declared in the resource section. I would still like to know the answer to that, but since my class derives from FrameworkElement, I don't need to declare it in the resource section; I can put it directly in the tree. This causes it to be instantiated AND inherit the DataContext.

Related

DataTemplateSelector CreateContent throws InvalidOperationException

I am in the process of making a custom horizontally scrollable ListView type control, I have come across an issue which I can't explain, and I'm not 100% sure that the issue is even with my code, unless I have misunderstood something.
I have distilled the issue into the simplest form I can, available at https://github.com/sparkeh9/XamarinFormsListViewIssue.
So, I have a HorizontalListView control utilising a very simple data template selector (no logic, returns a single data template)
See XAML screenshot
See Template Selector screenshot
My issue is, when I use a template selector, when calling ItemTemplateSelector.CreateContent() in order to start generating UI controls based on the template, it throws an exception See exception screenshot which claims that the LoadTemplate property should not be null. I have looked at the base classes and found that this property is a Func<object> which is private, and can only be set from outside by calling a specific constructor.
If I specify a literal item template in the XAML, everything works as expected, such as:
<controls:HorizontalListView.ItemTemplate>
<DataTemplate>
<Label Text="test"></Label>
</DataTemplate>
</controls:HorizontalListView.ItemTemplate>
EDIT: Answered my own question
I figured out what I had done wrong - if the type is DataTemplateSelector, then you must first generate a template by calling ItemTemplateSelector.SelectTemplate( item, null ), after which point you can call CreateContent()
diff
I've committed this to demonstrate what I mean:
https://github.com/sparkeh9/XamarinFormsListViewIssue/commit/f2f0d807d2d463d1fe9e6a89f0d3c0c7676a0761

How to programmatically change binding when datacontext changes

I have a custom control that allows the consumer to send in markup that will be parsed into Inlines, and it will try to match a given Command name with its appropriate ICommand. I have this working except in the case where the DataContext is not set yet. I know that storing the markup and reloading it upon DataContextChanged is not appropriate, but I cannot seem to find anything that works yet. I have tried BindingExpression and Binding to no avail as I do not see a way to attach them to a Hyperlink
I know that storing the markup and reloading it upon DataContextChanged is not appropriate
If you're going to be building a binding to ICommand instances within the DataContext, this is likely the only option that will make sense.
Otherwise, you'd never be able to correct the binding when the data context is changed.
Looking into some other code, I realized that this is all I needed to do:
hyperlink.SetBinding(Hyperlink.CommandProperty, new Binding(description.Command));
The WPF code picks it up generically...I will need to reflect to see exactly what it does, but it works. I could not set the Command property directly, but this worked :)

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).

How can I retrieve name(Key) of applied template?

I have a template assigned to a button:
<Button x:Name="btn_PatMat" Template="{StaticResource PatMat_Button}" ...
How can I retrieve the Key/String/Name of this template from said button?
Pseudocode:
String = btn_PatMat.Template.???.ToString()
You can't. At least not in the way you're trying.
To quote from this SO post about x:Key (emphasis mine):
x:Key is used for items that are being added as values to a
dictionary, most often for styles and other resources that are being
added to a ResourceDictionary. When setting the x:Key attribute,
there is actually no corresponding property on the object or even an
attached dependency property being set. It is simply used by the
XAML processor to know what key to use when calling Dictionary.Add.
StaticResources are evaluated during loading, so once the control loads, the Template property is no longer set to a binding, but is instead set to a copy of the ControlTemplate from your Resources, and no corresponding property on that object is set to the key.
You can verify this by checking out the XAML of the button after it's loaded, by using something like XamlWriter.Save to view it's XAML string.
The only solution I can think of that might work would be to loop through your .Resources, and find a ControlTemplate that is equal to your Button's ControlTemplate. I haven't tested this, and it probably isn't very practical for large resource libraries, but it may be an option.
But a better solution would probably be to change your logic so the key value can be accessed some other way by whatever object needs it.
Well I'm afraid that's not possible because it's not intended by WPF. There are some people which wanted to get access to x:Name which is similar to x:Key, they all had to give up.
Pls have a look at this SO post and this additional link.
The only workaround I could imagine is reading all templates from the ResourceDictionary, instantiate each resource (if possible), find the template (if it's e.g. a style) and compare it with the current instance of the template found in the control. But this seems to be a pretty ugly solution and I'm not sure if it'll work without any problems.

Pass through bound properties to the ViewModel

I'm still trying to wrap my head around some of the finer points of using WPF and MVVM. One thing that has bugged me for a while is how to get values from the View into the ViewModel. Let me explain the scenario.
I have a Window with several UserControls inside. One of those UserControls has a DependencyProperty of type TimeSpan named CurrentTime. It is bound (in the XAML for the window) to the Window's ViewModel.
Now, I also have a ViewModel for the UserControl. It needs access to the CurrentTime property in order to create objects based off it. How do I get that value into my ViewModel? I see a couple of options:
The simplest is probably just to pass the View into the ViewModel's constructor (or somehow otherwise reference the View from the ViewModel). But that seems so wrong and not WPF/MVVMy.
I could use messaging to actually get the CurrentTime from the other ViewModel. This would certainly work, but seems like overkill.
I could set up a binding in the XAML of the UserControl to bind, OneWayToSource, between the DP and the property in the ViewModel. I can't figure out exactly how to set that up (how do you reference a UserControl's new properties in its own XAML?), but it seems like it could work.
Am I missing any other options? Which of the above (or ones I missed) is the best way to do this?
I read through this thread here on SO, because it was similar, but the answers didn't really answer my question - I would love to do it with bindings or commands or something, but I just can't figure out how exactly.
The third option is the way to go here, but you'll have to specify binding in the code-behind of your UserControl:
public partial class MyUserControl : UserControl
{
public MyUserControl() {
InitializeComponent();
SetBinding(MyPropertyProperty,
new Binding {Path = new PropertyPath("MyViewModelProperty"), Mode = BindingMode.OneWayToSource});
}
}

Categories