77

While using WPF I noticed that when I add a control to a XAML file, the default constructor is called.

Is there a way to call a parameterized constructor?

g t
  • 7,287
  • 7
  • 50
  • 85
Hani
  • 1,517
  • 5
  • 20
  • 28
  • please take a look at my question http://stackoverflow.com/questions/15735830/wpf-best-practice-of-registering-a-delegatecommand-to-a-compositecommand – eran otzap Mar 31 '13 at 23:58

4 Answers4

75

.NET 4.0 brings a new feature that challenges the answer - but apparently only for UWP applications (not WPF).

x:Arguments Directive

<object ...>
    <x:Arguments>
        oneOrMoreObjectElements
    </x:Arguments>
</object>
StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Raskal
  • 759
  • 5
  • 2
  • Nice, I'm glad you brought this up. – Jeff Mercado Aug 21 '10 at 10:43
  • 33
    For anyone else who came here looking for exactly this answer, I'll save you some time because you're about to find this post next: http://stackoverflow.com/questions/14347181/how-to-fix-xaml2009-language-construct-is-not-allowed-here – Kevek Jan 22 '14 at 21:03
  • 6
    "Basically no current compiler (WPF, SL, WinRT) actually supports it" - Duncan Matheson. Linked by Kevek's comment, should be in the answer. – David Jun 28 '16 at 11:47
  • What is that `x` namespace defined to? – jpmc26 Mar 29 '18 at 19:22
  • 3
    Unfortunately this syntax is for XAML 2009 version which means Universal apps, and does not work in WPF sadly. – Amir Mahdi Nassiri Apr 01 '18 at 06:51
35

One of the guiding principles of XAML-friendly objects is that they should be completely usable with a default constructor, i.e., there is no behavior that is only accessible when using a non-default constructor. To fit with the declarative nature of XAML, object parameters are specified via property setters. There is also a convention that says that the order in which properties are set in XAML should not be important.

You may, however, have some special considerations that are important to your implementation but at odds with convention:

  1. You may have one or more properties which must be set before the object can be used.
  2. Two or more properties may be mutually exclusive with each other, e.g., it makes no sense to set both the StreamSource and UriSource of an image.
  3. You may want to ensure that a property is only set during initialization.
  4. One property may depend on another, which can be tricky due to the aforementioned convention of order independence when setting properties.

To make it easier to handle these cases, the ISupportInitialize interface is provided. When an object is read and created from XAML (i.e., parsed), objects implementing ISupportInitialize will be handled specially:

  1. The default constructor will be called.
  2. BeginInit() will be called.
  3. Properties will be set in the order they appeared in the XAML declaration.
  4. EndInit() is called.

By tracking calls to BeginInit() and EndInit(), you can handle whatever rules you need to impose, including the requirement that certain properties be set. This is how you should handle creation parameters; not by requiring constructor arguments.

Note that ISupportInitializeNotification is also provided, which extends the above interface by adding an IsInitialized property and Initialized event. I recommend using the extended version.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Mike Strobel
  • 25,075
  • 57
  • 69
10

No. Not from XAML [when using WPF].

Jack Ukleja
  • 13,061
  • 11
  • 72
  • 113
Alun Harford
  • 3,086
  • 18
  • 25
10

Yes, you can do it by the ObjectDataProvider. It allows you to call non-default constructor, for example:

<Grid>
    <Grid.Resources>
        <ObjectDataProvider x:Key="myDataSource"
                            ObjectType="{x:Type local:Person}">
            <ObjectDataProvider.ConstructorParameters>
                <system:String>Joe</system:String>
            </ObjectDataProvider.ConstructorParameters>
        </ObjectDataProvider>
    </Grid.Resources>
    <Label Content="{Binding Source={StaticResource myDataSource}, Path=Name}"></Label>
</Grid>

assuming that Person is

public class Person
{
    public Person(string Name)
    {
        this.Name = Name;
    }
    public string Name { get; set; }
}

Unfortunately, you cannot bind the ConstructorParameters. See some workaround here.

Pang
  • 9,564
  • 146
  • 81
  • 122
chviLadislav
  • 1,204
  • 13
  • 15