[英]Catel: multiple ViewModels with one View. Is it possible?
我得到了用户控件的ViewModel的通用基类:
public class SuggestModule<TEntity> : ViewModelBase
where TEntity : class, ISuggestable, new()
{
public SuggestModule(ISomeService someService)
{
// Some logic
}
// Some private fields, public properties, commands, etc...
}
}
Whitch有许多可继承的类。 例如,其中有两个:
public class CitizenshipSuggestViewModel : SuggestModule<Citizenship>
{
public CitizenshipSuggestViewModel(ISomeService someService)
: base(someService) { }
}
public class PlaceOfBirthSuggestViewModel : SuggestModule<PlaceOfBirth>
{
public PlaceOfBirthSuggestViewModel(ISomeService someService)
: base(someService) { }
}
那就是视图的实现:
<catel:UserControl
x:Class="WPF.PRC.PBF.Views.UserControls.SuggestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://schemas.catelproject.com"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:pbf="clr-namespace:WPF.PRC.PBF">
<Grid>
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"> />
<ListBox ItemsSource="{Binding ItemsCollection}" />
// Other elements, behaviors, other extensive logic...
</Grid>
</catel:UserControl>
现在,在MainWindow中创建两个ContentControls:
<catel:Window
x:Class="WPF.PRC.PBF.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://schemas.catelproject.com">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" Content="{Binding CitizenshipSuggestViewModel, Converter={catel:ViewModelToViewConverter}}" />
<ContentControl Grid.Row="1" Content="{Binding PlaceOfBirthSuggestViewModel, Converter={catel:ViewModelToViewConverter}}" />
</Grid>
</catel:Window>
由于违反命名约定,请在App.xaml.cs中手动解析ViewModel:
var viewModelLocator = ServiceLocator.Default.ResolveType<IViewModelLocator>();
viewModelLocator.Register(typeof(SuggestUserControl), typeof(CitizenshipSuggestViewModel));
viewModelLocator.Register(typeof(SuggestUserControl), typeof(PlaceOfBirthSuggestViewModel));
var viewLocator = ServiceLocator.Default.ResolveType<IViewLocator>();
viewLocator.Register(typeof(CitizenshipSuggestViewModel), typeof(SuggestUserControl));
viewLocator.Register(typeof(PlaceOfBirthSuggestViewModel), typeof(SuggestUserControl));
但是现在我有两个具有相同ViewModel的视图。 如何在不创建相同视图且每个视图都重复代码的情况下解决此问题?
先感谢您!
一种可能性是,例如,在您的UserControl代码后面创建DependencyProperty
#region Properties
public string Test
{
get { return (string)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
#endregion Properties
#region Dependency Properties
public static readonly System.Windows.DependencyProperty TestProperty =
System.Windows.DependencyProperty.Register("Test", typeof(string), typeof(YourUserControl), new System.Windows.FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
#endregion Dependency Properties
然后在您的xaml中,您可以将该属性绑定为:
<TextBlock Text="{Binding Test, RelativeSource={RelativeSource AncestorType={x:Type catel:UserControl}, Mode=FindAncestor}}">
然后在您的MainWindow中,您可以编写:
<views:YourUserControlName Test="{Binding SomeTextPropertyFromMainWindowVM}"/>
因此,您将能够从windowVM中的SomeTextPropertyFromMainWindowVM属性绑定到userControl中的某些属性。
如果在主窗口中有多个viewModel,则可以这样编写:
<views:YourUserControlName Test="{Binding SomeViewModel.SomeTextProperty}"/>
<views:YourUserControlName Test="{Binding SomeOtherViewModel.SomeTextProperty}"/>
您有几种选择:
再说一遍,所以如果将来需要自定义,则只需自定义1,而无需太多开销。 缺点是,如果需要检查常规行为,则需要全部更改。
创建一个代表VM代表状态的枚举。 在这种情况下,你可以简单地创造能够抓住所有的,你需要处理的情况下, 单个虚拟机。 您可以使用视图上的依赖项属性并使用ViewToViewModelMapping
自动将此映射到vm来解决此问题。 这与您希望通过视图实现的代码重用最接近。 它确实与“关注点分离”背道而驰,但是由于它代表相同类型的数据,所以我认为它仍然是一种好方法。
对于2,您需要执行以下操作:
1使用PlaceOfBirth
, Citizenship
等创建一个枚举SuggestEntityType
2在vm上创建一个属性(此示例代码假设您使用的是Catel.Fody):
public SuggestedEntityType EntityType { get; set; }
3在视图上创建一个依赖项属性:
[ViewToViewModel(MappingType = ViewToViewModelMappingType.ViewToViewModel)]
public SuggestedEntityType EntityType
{
get { return (SuggestedEntityType) GetValue(EntityTypeProperty); }
set { SetValue(EntityTypeProperty, value); }
}
public static readonly DependencyProperty EntityTypeProperty = DependencyProperty.Register("EntityType", typeof (SuggestedEntityType),
typeof (MyControl), new PropertyMetadata(null));
4现在,您可以像这样使用用户控件:
<controls:MyView EntityType="Citizenship" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.