繁体   English   中英

卡特尔:具有一个视图的多个ViewModel。 可能吗?

[英]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. 再说一遍,所以如果将来需要自定义,则只需自定义1,而无需太多开销。 缺点是,如果需要检查常规行为,则需要全部更改。

  2. 创建一个代表VM代表状态的枚举。 在这种情况下,你可以简单地创造能够抓住所有的,你需要处理的情况下, 单个虚拟机。 您可以使用视图上的依赖项属性并使用ViewToViewModelMapping自动将此映射到vm来解决此问题。 这与您希望通过视图实现的代码重用最接近。 它确实与“关注点分离”背道而驰,但是由于它代表相同类型的数据,所以我认为它仍然是一种好方法。

对于2,您需要执行以下操作:

1使用PlaceOfBirthCitizenship等创建一个枚举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" />

有关更多信息,请参见http://docs.catelproject.com/vnext/catel-mvvm/view-models/mapping-properties-from-view-to-view-model/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM