How to do the equivalent of {Binding Source} in code?

TC2254TC2254 USMember
edited March 2016 in Xamarin.Forms

I'm extending a control to be able to reuse it across my current Xamarin project. As part of this control, I need to create a DataTemplate programmatically. I have this part figured out and it works ok.

The DataTemplate has a Label in it. I need to bind the Label's BindingContext property to {Binding Source}. I need to bind the Label's Text property to {Binding Path=Name}.

This works in XAML, but I don't want to have to copy it to a million different places in the code base.
<dxGrid:TemplateColumn FieldName="MyPropertyName" Caption="MyColumn"> <dxGrid:TemplateColumn.DisplayTemplate> <DataTemplate> <Label BindingContext="{Binding Source}" Text="{Binding Source, Path=MyPropertyName}" /> </DataTemplate> </dxGrid:TemplateColumn.DisplayTemplate>

My extended control looks like this right now:
`public class MyColumn : TemplateColumn
{
public MyColumn()
{
DataTemplate displayTemplate = new DataTemplate(() =>
{
BindingBase textBinding = new Binding(FieldName);

            Label label = new Label();

            // TODO: Bind BindingContextProperty to {Binding Source}
            //label.SetBinding(BindingContextProperty, binding);

            label.SetBinding(Label.TextProperty, textBinding);
            return new ViewCell
            {
                View = label
            };
        });

        DisplayTemplate = displayTemplate;
    }
}`

I'm getting hung up in the binding because I'm not sure how to do the equivalent of {Binding Source} in code. Any help would be appreciated.

This question was originally posted to StackOverflow here: http://stackoverflow.com/questions/35808706/how-to-do-the-equivalent-of-binding-source-in-code

Tagged:

Posts

  • TC2254TC2254 USMember
    edited March 2016

    @AdamP Thanks for the response. Unfortunately this does not work as there is no "Source" property on the TemplateColumn. If I set it to a string "Source", then it fails with a Null Reference Exception. I made another pass at it this morning and got it working this way:

    public MyColumn()
    {
        DataTemplate displayTemplate = new DataTemplate(() =>
        {
            Grid grid = new Grid();
            grid.SetBinding(Grid.BindingContextProperty, "Source");
    
            Label label = new Label();
            label.SetBinding(Label.TextProperty,FieldName);
    
            grid.Children.Add(label);
    
            return grid;
        });
    
        this.DisplayTemplate = displayTemplate;
    }
    
  • AdamPAdamP AUUniversity ✭✭✭✭✭

    @TC2254 - glad you managed to get it working. Apologies, I missed the fact it was in a DataTemplate.

  • ShimmyWeitzhandlerShimmyWeitzhandler USMember ✭✭✭

    Is there also any way to perform GetBinding? I want to get the actual Binding (i.e. the property name), not the value.
    Anyone?

  • SteveShaw.5557SteveShaw.5557 USMember ✭✭✭
    edited December 2017

    @ShimmyWeitzhandler - Neither BindingContext nor BindableObject have any methods that would help you search for a binding, so I believe the answer is "No". AFAIK, you would have to create the bindings in code (not XAML), and create your own association (dictionary) between views (or viewmodels?) and binding names. Maybe you can create and cache the BindableProperties involved in the bindings?

  • GaetanFGaetanF USMember ✭✭✭

    @SteveShaw.5557 - You actually CAN create a binding in XAML and use it later. It can be cached in the resource dictionary (which I recommend if you are switching bindings at runtime) or created in place. Here is a simple example:

    <Binding x:Key="MyKeyIfInResDic" Path="The.Property" Converter="{StaticResource MyStaticConverter}" />

    If you are following the MVVM principles, no ViewModel should ever have to bother with creating/setting/caching bindings, if you'd ask me.

  • SteveShaw.5557SteveShaw.5557 USMember ✭✭✭
    edited March 22

    @GaetanF - that is useful to know, thanks.

    Given that, the answer to Shimmy, is to go about it a different way. While AFAIK it isn't possible to do what he asked, if the goal is to be able to switch between bindings, then instead of trying to access property names, using resources and their names is a good solution.


    The way I read his question, he was trying to get information (in code behind) about the DependencyProperty that was attached to a binding, once a BindingContext was attached. He asked for a GetBinding equivalent to SetBinding - BindableObject.SetBinding(BindableProperty, BindingBase). Or perhaps a BindableObjectExtensions.SetBinding method that takes a string.

    What you suggest is much cleaner (if it solves the need). You have resource objects, each of which is a System.Windows.Data.Binding. Set a UI property to one of those at runtime, and let internal code hook that up to the DependencyProperty described by Binding's Path.

    To attach to a different DependencyProperty, use a binding with a different path (or change the path property of the binding?)

    It isn't GetBinding functionality, but it allows some interesting "Set" scenarios.


    This raises a question I don't know the answer to:

    Could GetBinding be approximated this way:

    • Code-behind gets value of some UI property, as defined in XAML.
    • Determine that the UI property has an attached binding.
    • If so, get Path property of that binding.
    • Later, to set the UI property back to that same binding, pass that path as a parameter to SetBinding.

    If this is possible, what would the code for those steps look like?

    (To keep it simple, NOT inside of a DataTemplate, which is what TC2254 asked about.)

    I don't have a reason to test this right now, but something like this?

    <Label x:Name="myLabel" Text="{Binding MyText}">
    

    in code-behind:

    // ... not quite right ...
    var prop = myLabel.TextProperty;   // type is BindableProperty
    var binding = ?? how get attached binding, if any ??
    string path = binding.Path;   // "MyText"?
    
    // Set myLabel's Text to something else...
    ...
    
    // Later, to restore original binding.
    myLabel.SetBinding(Label.TextProperty, path);
    

    NOTE: I'm not suggesting this is a good idea, even if possible. Just exploring the limits of what is possible, to better understand working with XAML.

Sign In or Register to comment.