Catel为嵌套视图设置DataContext

时间:2016-09-21 08:49:34

标签: c# wpf xaml mvvm catel

请帮助我解决问题。为什么带签名的构造函数不起作用。以及如何为ServerTabView确定DataContext?据我所知,现在ServerTabView的DataContext继承自父 - MainWindowView,因为ServerTabView嵌套在其中。那么如何获得接收ServerTabView DataContext的权利?

MainWindowView

<catel:DataWindow x:Class="ServerUI.Views.MainWindowView"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:catel="http://catel.codeplex.com"
              xmlns:views="clr-namespace:ServerUI.Views"
              Width="640"
              Height="480"
              ResizeMode="CanResize"
              ShowInTaskbar="True"
              SizeToContent="Manual"
              WindowStartupLocation="Manual"
              WindowState="Normal">

<!--  Resources  -->
<catel:DataWindow.Resources />

<catel:TabControl TabStripPlacement="Left">
    <TabItem Header="__Server__">
        <views:ServerTabView DataContext="{Binding}" />
    </TabItem>
    <TabItem Header="__Clients_">
        <views:ClientsTabView DataContext="{Binding}" />
    </TabItem>
</catel:TabControl>

</catel:DataWindow>

ServerTabView

<catel:UserControl x:Class="ServerUI.Views.ServerTabView"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:catel="http://catel.codeplex.com">

<catel:StackGrid>
    <catel:StackGrid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </catel:StackGrid.RowDefinitions>

    <catel:StackGrid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </catel:StackGrid.ColumnDefinitions>

    <Label Content="IP Address" />
    <TextBox Text="{Binding ServerIpAddress}" />

    <Label Content="Port" />
    <TextBox Text="{Binding ServerPort}" />

    <Label Content="Directory" />
    <TextBox Text="{Binding Catalogue}" />

    <catel:EmptyRow />

    <Button Grid.ColumnSpan="2"
            Command="{Binding StartServer}"
            Content="Start" />

    <Button Grid.ColumnSpan="2"
            Command="{Binding StopServer}"
            Content="Stop" />
</catel:StackGrid>

</catel:UserControl>

ServerTabViewModel

    public class ServerTabViewModel : ViewModelBase
    {
        private readonly IServerServices _serverServices;

        public ServerTabViewModel(Server server, IServerServices serverServices)
        {
            Argument.IsNotNull(() => serverServices);
            Argument.IsNotNull(() => server);

            _serverServices = serverServices;
            Server = server;

            StartServer = new TaskCommand(OnStartServerExecuteAsync);
            StopServer = new TaskCommand(OnStopServerExecuteAsync);
        }

        #region Properties
        /// <summary>
        /// Gets or sets the property value.
        /// </summary>
        [Model]
        public Server Server
        {
            get { return GetValue<Server>(ServerProperty); }
            set { SetValue(ServerProperty, value); }
        }
        // ModelToViewModel Properties
        //...
   }

一些调试信息:

11:57:00:464 => [DEBUG] [Catel.MVVM.Providers.LogicBase] [10] DataContext of TargetView 'ServerTabView' has changed to 'MainWindowViewModel'
11:57:00:466 => [DEBUG] [Catel.MVVM.Providers.LogicBase] [10] Using IViewModelFactory 'Catel.MVVM.ViewModelFactory' to instantiate the view model
11:57:00:466 => [DEBUG] [Catel.IoC.TypeFactory] [10] Creating instance of type 'ServerUI.ViewModels.ServerTabViewModel' using specific parameters. No constructor found in the cache, so searching for the right one
11:57:00:467 => [DEBUG] [Catel.IoC.TypeFactory] [10] Checking if constructor 'public ctor(Server server, IServerServices serverServices)' can be used
11:57:00:468 => [DEBUG] [Catel.IoC.TypeFactory] [10] Constructor is not valid because value 'ServerUI.ViewModels.MainWindowViewModel (ID = 1)' cannot be used for parameter 'ServerUI.ViewModels.MainWindowViewModel (ID = 1)'
11:57:00:468 => [DEBUG] [Catel.IoC.TypeFactory] [10] The constructor is valid and can be used
11:57:00:469 => [DEBUG] [Catel.IoC.TypeFactory] [10] No constructor could be used, cannot construct type 'ServerUI.ViewModels.ServerTabViewModel' with the specified parameters
11:57:00:469 => [DEBUG] [Catel.IoC.TypeFactory] [10] Creating instance of type 'ServerUI.ViewModels.ServerTabViewModel' using specific parameters. No constructor found in the cache, so searching for the right one
11:57:00:469 => [DEBUG] [Catel.IoC.TypeFactory] [10] Checking if constructor 'public ctor(Server server, IServerServices serverServices)' can be used
11:57:00:470 => [DEBUG] [Catel.IoC.TypeFactory] [10] Constructor is not valid because parameter 'server' cannot be resolved from the dependency resolver
11:57:00:470 => [DEBUG] [Catel.IoC.TypeFactory] [10] The constructor is valid and can be used
11:57:00:470 => [DEBUG] [Catel.IoC.TypeFactory] [10] No constructor could be used, cannot construct type 'ServerUI.ViewModels.ServerTabViewModel' with the specified parameters
11:57:00:471 => [DEBUG] [Catel.MVVM.ViewModelFactory] [10] Could not construct view model 'ServerUI.ViewModels.ServerTabViewModel' using injection of data context 'MainWindowViewModel'
11:57:00:471 => [DEBUG] [Catel.MVVM.Providers.LogicBase] [10] Used IViewModelFactory to instantiate view model, the factory did NOT return a valid view model
System.Windows.Data Error: 3 : Cannot find element that provides DataContext. BindingExpression:(no path); DataItem=null; target element is 'ClientsTabView' (Name=''); target property is 'DataContext' (type 'Object')

结果如何 - ServerTabViewModel(Server server, IServerServices serverServices)不要启动。

更新 _____________________________________________________________________

MainWindowViewModel

public class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
    }

    public override string Title => "WatcherServerUI";
}

我应该如何在这里实例Server?我的意思是,对此有什么好处?

1 个答案:

答案 0 :(得分:0)

正如您在日志记录中看到的,嵌套视图的当前DataContext(在本例中为ServerTabViewClientsTabView)为MainWindowViewModel

在Catel中构建视图模型有三种方式:

  1. 使用显式模型注入(然后需要设置DataContext)
  2. 从IoC容器自动解析
  3. 1和2的组合
  4. 由于您在视图模型中为其他注入服务指定了Server参数,因此您选择选项3.这意味着您需要将DataContext设置为有效Server宾语。您尚未发布MainWindowViewModel的代码,但我们假设该虚拟机上有一个名为Server的公共媒体资源。

    <TabItem Header="__Server__">
        <views:ServerTabView DataContext="{Binding Server}" />
    </TabItem>
    

    正如您所看到的,不是传递{Binding}(导致MainWindowViewModel),而是应该使用{Binding Server}来生成服务器实例,并将用于实例化嵌套视图模型