0

Ok I find it weird that I cannot seem to find this anywhere. I come from an Angular environment where I could simply do

<my-component [someProperty]="someValue"></my-component>

where someValue is not the string 'someValue' but could be an object.

Now in WPF I am struggling to do something similar.

Suppose I have a control child-control that needs a list of strings.

public partial class ChildControl: UserControl {
   public List<string> Names {get;set;}
}

I also have a control 'parent-control' where in the ParentControl.xaml.cs file the following list is declared

class ParentControl {
    public List<string> someList = new List<string>() { "A", "B" };
}

and I would now like to inject this list in the child control. So my ParentControl.xaml file looks like this

<UserControl
   ...>
    <child-control
      Names="someList"
    >
    </child-control>
</UserControl>

This throws an error.

ArgumentException: Object of type 'System.String' cannot be converted to type 'System.Collections.Generic.List`1[System.String]'.

So it inserts the string 'someList' instead of the object. I also tried stuff like

<child-control
  Names="{Binding someList}"
>
</child-control>

But this then throws the error

A 'Binding' can only be set on a DependencyProperty of a DependencyObject.'

This seems like such a trivial thing to do. Yet I cannot find it anywhere. They either use built-in controls which is not my case or they do the weirdest stuff ever simply to pass a value to a control. Some of this weird stuff is to declare this variable twice as a dependency property in both child and parent component. How can it be that passing a variable is so cumbersome? There clearly must be a more elegant way.

1 Answers1

1

The Names property must be defined as a dependency property for you to be able to bind something to it:

public partial class ChildControl : UserControl
{
    public ChildControl()
    {
        InitializeComponent();
        SetValue(NamesProperty, new List<string>());
    }

    public static readonly DependencyProperty NamesProperty =
        DependencyProperty.Register(
          name: nameof(Names),
          propertyType: typeof(List<string>),
          ownerType: typeof(ChildControl)
        );

    public List<string> Names
    {
        get => (List<string>)GetValue(NamesProperty);
        set => SetValue(NamesProperty, value);
    }
}

The XAML markup could then be defined something like this:

<UserControl Name="parent" ...>
    <local:ChildControl Names="{Binding someList, ElementName=parent}" />
</UserControl>

Also note that you can only bind to public properties so you also need to turn someList into a property (and consider changing its name to SomeList to comply with the naming guidelines):

public List<string> someList { get; } = new List<string>() { "A", "B" };
mm8
  • 163,881
  • 10
  • 57
  • 88