Catel 为嵌套视图设置 DataContext
Catel setting DataContext for nested view
请帮我解决一个问题。为什么带有签名的构造函数不起作用。以及如何确定 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
?我的意思是,什么是好的方法?
如您在日志记录中所见,嵌套视图(在本例中为 ServerTabView
和 ClientsTabView
)的当前 DataContext 为 MainWindowViewModel
。
可以通过 3 种方式在 Catel 中构建视图模型:
- 使用显式模型注入(然后需要设置 DataContext)
- 从 IoC 容器自动解析
- 1 和 2 的组合
由于您在视图模型中指定了带有附加注入服务的 Server
参数,因此您选择了选项 3。这意味着您需要将 DataContext
设置为有效的 Server
对象。您尚未发布 MainWindowViewModel
的代码,但我们假设该虚拟机上有一个名为 Server
的 public 属性。
<TabItem Header="__Server__">
<views:ServerTabView DataContext="{Binding Server}" />
</TabItem>
如您所见,您应该使用 {Binding Server}
而不是传递 {Binding}
(这会导致 MainWindowViewModel
),这会导致服务器实例并将用于实例化嵌套查看模型。
请帮我解决一个问题。为什么带有签名的构造函数不起作用。以及如何确定 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
?我的意思是,什么是好的方法?
如您在日志记录中所见,嵌套视图(在本例中为 ServerTabView
和 ClientsTabView
)的当前 DataContext 为 MainWindowViewModel
。
可以通过 3 种方式在 Catel 中构建视图模型:
- 使用显式模型注入(然后需要设置 DataContext)
- 从 IoC 容器自动解析
- 1 和 2 的组合
由于您在视图模型中指定了带有附加注入服务的 Server
参数,因此您选择了选项 3。这意味着您需要将 DataContext
设置为有效的 Server
对象。您尚未发布 MainWindowViewModel
的代码,但我们假设该虚拟机上有一个名为 Server
的 public 属性。
<TabItem Header="__Server__">
<views:ServerTabView DataContext="{Binding Server}" />
</TabItem>
如您所见,您应该使用 {Binding Server}
而不是传递 {Binding}
(这会导致 MainWindowViewModel
),这会导致服务器实例并将用于实例化嵌套查看模型。