简体   繁体   中英

Catel ViewModel is not created

I have a calel:Usercontrol which will be a sidebar with overrided GetViewModelType() method.

Additionally I have dependencyProperty to set Model Item.

Problem is that my ViewModel is never initialized.

I don't know why, but other controls View Models are initialized properly.

This is how I have done that:

In parent View:

<itemSideBar:ItemSidebarView Grid.Column="1" PlaceItem="{Binding ElementName=itemsList, Path=SelectedItem}"></itemSideBar:ItemSidebarView>

My sideBar control codeBehind:

using Catel.Windows.Controls;

/// <summary>
/// Interaction logic for ItemSidebarView.xaml.
/// </summary>
public partial class ItemSidebarView : UserControl
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ItemSidebarView"/> class.
    /// </summary>
    public ItemSidebarView()
    {
        InitializeComponent();

    }

    protected override Type GetViewModelType()
    {
        return typeof (ItemSideBarViewModel);
    }

    public static readonly DependencyProperty PlaceItemProperty = DependencyProperty.Register(
        "PlaceItem", typeof (PlaceItem), typeof (ItemSidebarView), new PropertyMetadata(default(PlaceItem)));

    public PlaceItem PlaceItem
    {
        get { return (PlaceItem) GetValue(PlaceItemProperty); }
        set { SetValue(PlaceItemProperty, value); }
    }
}

And my SideBarViewModel

using Catel.MVVM;

/// <summary>
/// UserControl view model.
/// </summary>
public class ItemSideBarViewModel : ViewModelBase
{
    public ItemSideBarViewModel()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ItemSideBarViewModel"/> class.
    /// </summary>
    public ItemSideBarViewModel(PlaceItem item)
    {
        PlaceItem = item;
    }

    /// <summary>
    /// Gets the title of the view model.
    /// </summary>
    /// <value>The title.</value>
    public override string Title { get { return "View model title"; } }

    /// <summary>
    /// Gets or sets the property value.
    /// </summary>
    [Model]
    public PlaceItem PlaceItem
    {
        get { return GetValue<PlaceItem>(PlaceItemProperty); }
        set { SetValue(PlaceItemProperty, value); }
    }

    /// <summary>
    /// Register the PlaceItem property so it is known in the class.
    /// </summary>
    public static readonly PropertyData PlaceItemProperty = RegisterProperty("PlaceItem", typeof (PlaceItem), null);

    // TODO: Register models with the vmpropmodel codesnippet
    // TODO: Register view model properties with the vmprop or vmpropviewmodeltomodel codesnippets
    // TODO: Register commands with the vmcommand or vmcommandwithcanexecute codesnippets
}

Could you explain me how it should work? I have done the same with ListBox items and its working.

Edit: In logs I can see:

12:37:59:829 => [DEBUG] [Catel.IoC.TypeFactory] Creating instance of type 'EliteCard.ViewModels.TabList.ItemSideBar.ItemSideBarViewModel' using specific parameters. No constructor found in the cache, so searching for the right one
12:37:59:830 => [DEBUG] [Catel.IoC.TypeFactory] Checking if constructor 'public ctor(PlaceItem place)' can be used
12:37:59:830 => [DEBUG] [Catel.IoC.TypeFactory] Constructor is not valid because value 'EliteCard.ViewModels.TabList.TabListViewModel' cannot be used for parameter 'EliteCard.ViewModels.TabList.TabListViewModel'
12:37:59:831 => [DEBUG] [Catel.IoC.TypeFactory] The constructor is valid and can be used
12:37:59:831 => [DEBUG] [Catel.IoC.TypeFactory] No constructor could be used, cannot construct type 'EliteCard.ViewModels.TabList.ItemSideBar.ItemSideBarViewModel' with the specified parameters
12:37:59:832 => [DEBUG] [Catel.IoC.TypeFactory] Creating instance of type 'EliteCard.ViewModels.TabList.ItemSideBar.ItemSideBarViewModel'. No constructor found in the cache, so searching for the right one.
12:37:59:832 => [DEBUG] [Catel.IoC.TypeFactory] Calling constructor.Invoke with the right parameters
12:37:59:834 => [DEBUG] [Catel.MVVM.ViewModelBase] Creating view model of type 'ItemSideBarViewModel' with unique identifier 3

You are using the view inside another view. Note that each view in Catel has its own view model.

As you can see in the log, it first tries the constructor with the most parameters (this with model injection). After that, it will use the empty constructor.

In your case, simply do the following:

1) remove the empty constructor (you don't want a view model without a context, right?)

2) Make sure to set a valid data context. Currently, the data context is that of the parent view, which is the parent view model. In the log, you can see because it says the current data context is TabListViewModel while your constructor is expecting a model of type PlaceItem .

You can set the data context like this:

<itemSideBar:ItemSidebarView Grid.Column="1" DataContext="{Binding ElementName=itemsList, Path=SelectedItem}" />

3) Remove the PlaceItem dependency property. It is not required. You can simply get the model from the view model in the view (if you need to do anything in the code-behind):

var vm = ViewModel as ItemSideBarViewModel;
if (vm != null)
{
    var myPlaceItem = vm.PlaceItem;
}

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