简体   繁体   中英

How to set the DataContext of a View in XAML with a ViewModel which needs the View as Parameter?

I want to create the ViewModel of my WPF Application in the XAML code. It's easy if you just have the default constructor, but I need the View as a Parameter, so I have to call the Constructor myself.

This is as far as I came:

<ObjectDataProvider ObjectType="{x:Type local:ViewModel}">
    <ObjectDataProvider.ConstructorParameters>
        <Binding Source="{RelativeSource Self}"/>
    </ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>

But with this there is an TargetInvocationException thrown, because ConstrutorParameter doesn't accept Binding :

"Binding" can not be used within a ParameterCollection collection. "Binding" can only be set on a "DependencyProperty" of a "DependencyObject".

Is there any way to convert "Self" to an object or something?

Self already points to an object. Your problem in this case is that ParameterCollection isn't a DependencyObject, ie it is not derived from the DependencyObject class and does not implement its properties as DependencyProperties as per the DependencyObject implementation convention, just as the error message suggests. To work around this, you could wrap the class ObjectDataProvider into a wrapper class that implements DependencyObject and takes the values you give here as constructor parameters as DependencyProperties. Then you could pass "self" or any other resource to one of these properties and initialize the ObjectDataProvider inside your wrapper, passing the value of the property to the constructor of ObjectDataProvider.

class ObjectDataProviderWrapper : DependencyObject {
    private ObjectDataProvider _objectDataProvider = null;
    public static DependencyProperty ControlProperty = DependencyProperty.Register(.... (look that up in the manual, it depends on your use case)

    public ObjectDataProvider DataProvider {
        get {
            if(_objectDataProvider == null) {
                _objectDataProvider = new ObjectDataProvider(ControlProperty.GetValue(this));
             }
            return _objectDataProvider;
        }
    }
....

Using the ObjectDataProvider later on in your Xaml then would require one additional level of indirection, ie you will have to dereference your wrapper, which could be done using a DataContext scope like for example:

<Grid DataContext="{Binding Source={StaticResource wrapper}, Path=DataProvider}" >
...
</Grid>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM