2017-08-07 87 views
0

我想通过使用ShowViewModel<ViewModel, Type>(parameter)传递一个对象列表作为参数在同一个viewmodel(递归)的不同实例之间传递参数。 我在我的MVVMCross/xamarin表单项目中遇到了这个错误。MvxException:无法构造和初始化ViewModel

MvvmCross.Platform.Exceptions.MvxException: Failed to construct and 
initialize ViewModel for type Project.Core.ViewModels.ObjectViewModel from locator MvxDefaultViewModelLocator - check InnerException for more information ---> MvvmCross.Platform.Exceptions.MvxException: Problem creating viewModel of type ObjectViewModel ---> MvvmCross.Platform.Exceptions.MvxIoCResolveException: Failed to resolve parameter for parameter obj of type ObjectItem when creating Project.Core.ViewModels.ObjectViewModel 
    at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.GetIoCParameterValues (System.Type type, System.Reflection.ConstructorInfo firstConstructor) [0x00036] in C:\projects\mvvmcross\MvvmCross\Platform\Platform\IoC\MvxSimpleIoCContainer.cs:502 
    at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.IoCConstruct (System.Type type) [0x0002c] in C:\projects\mvvmcross\MvvmCross\Platform\Platform\IoC\MvxSimpleIoCContainer.cs:312 
    at MvvmCross.Platform.Mvx.IocConstruct (System.Type t) [0x00006] in C:\projects\mvvmcross\MvvmCross\Platform\Platform\Mvx.cs:169 
    at MvvmCross.Core.ViewModels.MvxDefaultViewModelLocator.Load (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterValues, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00000] in C:\projects\mvvmcross\MvvmCross\Core\Core\ViewModels\MvxDefaultViewModelLocator.cs:33 

解释更多,这里是我的代码:

ObjectPage.xaml

<mvx:MvxContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
     xmlns:mvx="clr-namespace:MvvmCross.Forms.Core;assembly=MvvmCross.Forms" 
     x:Class="Project.Core.Pages.ObjectPage" 
     Title="Object"> 
<StackLayout> 
    <StackLayout> 
     <StackLayout Padding="5,5,5,5"> 
      <Label Text="{Binding SubTitle}" FontSize="21" VerticalOptions="End"></Label> 
     </StackLayout> 
     <StackLayout> 
      <ListView 
       ItemsSource="{Binding ObjectItems}" 
       SelectedItem="{Binding SelectedListItem, Mode=TwoWay}"> 
       <ListView.ItemTemplate> 
        <DataTemplate> 
         <ViewCell> 
          <Frame HasShadow="True" Margin="10"> 
           <StackLayout Margin="8"> 
            <Label Text="{Binding Title}"></Label> 
           </StackLayout> 
          </Frame> 
         </ViewCell> 
        </DataTemplate> 
       </ListView.ItemTemplate> 
      </ListView> 
     </StackLayout> 
    </StackLayout> 
</StackLayout> 

ObjectPage.xaml.cs

namespace Project.Core.Pages 
{ 
    public partial class ObjectPage 
    { 
     public ObjectPage (ObjectItem obj) 
     { 
      InitializeComponent(); 
      BindingContext = new ObjectViewModel(obj); 
     } 
    } 
} 

ObjectViewModel

namespace Project.Core.ViewModels 
{ 
    public class ObjectViewModel : ObjectItemViewModel 
    { 

     public ObjectViewModel(ObjectItem obj) : base(obj) 
     { 
     } 

     public override void ShowItem() 
     { 
       ShowViewModel<ObjectViewModel, ObjectItem>(Obj); 
     } 
    } 
} 

解释得:每个对象都有ObjectItems的列表。每个ObjectItem也有一个ObjectItems列表。 对象从ObjectItem继承。 下面是一个例子:

​​3210

要加载这些项目,我创建了一个类视图模型,从那里继承ObjectViewModel

ObjectItemViewModel.cs

namespace Project.Core.ViewModels 
{ 
    public class ObjectItemViewModel : MvxViewModel<ObjectItem> 
{ 
    public string Title => (this.Obj == null ? "/!\\ Titre" : this.Obj.Title); 
    public string SubTitle => (this.Obj == null ? "/!\\ Sous Titre" : this.Obj.SubTitle); 
    private List<ObjectItemViewModel> _ObjectItems; 
    public List<ObjectItemViewModel> ObjectItems 
     { 
      get => _ObjectItems; 

      set 
      { 
       _ObjectItems = value; 
       RaisePropertyChanged(() => ObjectItems); 
      } 
     } 
     private ObjectItem _Obj; 
     public ObjectItem Obj 
     { 
      get => _Obj; 
      set 
      { 
       _Obj= value; 
       RaisePropertyChanged(() => Obj); 
      } 
     } 
     public ObjectItemViewModel _selectedListItem; 
     public ObjectItemViewModel SelectedListItem 
     { 
      get 
      { 
       return _selectedListItem; 
      } 
      set 
      { 
       if (SetProperty(ref _selectedListItem, value)) 
        OnSelectedChangedCommand.Execute(value); 
      } 
     } 

     public ObjectItemViewModel(ObjectItem obj) 
     { 
      this.Obj = obj; 
      loadItems(); 
     } 

     private MvxCommand<ObjectItemViewModel> _onSelectedChangedCommand; 

     private ICommand OnSelectedChangedCommand 
     { 
      get 
      { 
       return _onSelectedChangedCommand ?? (_onSelectedChangedCommand = new MvxCommand<ObjectItemViewModel>((item) => 
       { 
        if (item == null) 
        { 
         Debug.WriteLine("Item null"); 

         return; 
        } 
        item.ShowItem(); 
       })); 
      } 
     } 


     public virtual void ShowItem() 
     { 
      //DO nothing 


     } 

     public void loadItems() 
     { 
      if (this.Obj != null && 
       this.Obj.ObjectItems != null && 
       this.Obj.ObjectItems.Count > 0) 
      { 
       ObjectItems = new List<ObjectItemViewModel>(); 
       foreach (ObjectItem objectItem in this.Obj.ObjectItems) 
       { 
        if (objectItem.MemoItems != null && objectItem.ObjectItems.Count == 1) 
        { 
         ObjectItems.Add(new InfoViewModel(objectItem)); 
        } 
        else 
        { 

         ObjectItems.Add(new ObjectViewModel(objectItem)); 
         Debug.WriteLine("Item crée" + objectItem.Title); 
        } 
       } 

      } 
     } 

     public override Task Initialize(ObjectItem parameter) 
     { 
      Obj = parameter; 
      return Task.FromResult(0); 

     } 
    } 
} 
+0

不仅仅是性能的观察 - 你有很多不必要的嵌套组布局的页面上。在页面的根部有一个在另一个里面,并且有一个包装列表视图。看看这个页面上的减少可视树大小部分https://developer.xamarin.com/guides/xamarin-forms/deployment-testing/performance/ –

回答

1

一切你把构造函数一个ViewModel,MvvmCross视为它需要通过依赖注入获得的东西。所以在你的情况下,因为ObjectItem未在MvvmCross IoC容器中注册,所以ShowViewModel无法解析并放入构造函数。

通常如何解决这个问题,是在ViewModel中使用Init方法,而不是在ShowViewModel调用中传递一个对象作为参数。

如果使用MvvmCross 5.x或更新的版本,当使用新的NavigationService时,这已经转变为Initialize,但是基本上差不多。

我认为在你的情况下,最快的方法是给你的ObjectViewModel添加一个空的构造函数。然后添加一个Init方法,其中您分配您的Obj道具并呼叫loadItems()类似于非空ctor。因此,像:

public class ObjectItemViewModel : MvxViewModel<ObjectItem> 
{ 
    public ObjectItemViewModel() { } 

    public void Init(ObjectItem obj) 
    { 
     Obj = obj; 
     loadItems(); 
    } 

    // rest of code 
} 

ObjectItemViewModel取出构造函数,然后进行ObjectViewModel这样的:

public class ObjectViewModel : ObjectItemViewModel 
{ 
    public override void ShowItem() 
    { 
     ShowViewModel<ObjectViewModel, ObjectItem>(Obj); 
    } 
} 
+0

是不是Initialize有什么用? – hanaa

+0

我已经实现了Initialize(查看ObjectItemViewModel的结尾)。我真的不明白你写了什么......你建议删除哪个构造函数? – hanaa

+0

只有在您使用NavigationService时才会调用Initialize,因此您不会在此处使用它,因此它不会被调用。你只需要添加一个空的ctor和Init方法......那怎么不清楚? – Cheesebaron