【问题标题】:Catel: multiple ViewModels with one View. Is it possible?Catel:多个 ViewModel 和一个 View。是否可以?
【发布时间】:2017-12-18 06:55:39
【问题描述】:

我的用户控件的 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 中创建两个 ContentControl:

<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 的视图。 如果不创建相同的视图并在每个视图中重复代码,我该如何解决这个问题?

提前谢谢你!

【问题讨论】:

标签: c# wpf mvvm user-controls catel


【解决方案1】:

你有几个选择:

  1. 重复自己,如果将来需要自定义,您可以只自定义 1 个,而无需太多开销。缺点是,如果您需要检查通用行为,则需要全部更改。

  2. 创建一个表示 VM 所表示状态的枚举。在这种情况下,您可以简单地创建一个 single vm 来捕获您需要处理的所有情况。您可以使用视图上的依赖属性并使用ViewToViewModelMapping 自动将其映射到虚拟机来解决此问题。这最接近于实现代码重用,正如您希望通过您的视图实现的那样。它确实有点反对“关注点分离”,但由于它代表相同类型的数据,我相信它仍然是一个好方法。

对于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" />

欲了解更多信息,请参阅http://docs.catelproject.com/vnext/catel-mvvm/view-models/mapping-properties-from-view-to-view-model/

【讨论】:

  • 谢谢你,吉尔特!我是一个初学者程序员,所以我对许多澄清问题表示歉意。我对你的理解有多正确?我需要创建类似“SuggestEntityTypes”的枚举:CitizenshipSuggesting、PlaceOfBirthSuggesting。比在我的 SuggestUserControl 的代码隐藏中创建依赖属性 SuggestEntityType。现在,在 MainWindow.xaml 中添加: 并且... 我应该在哪里使用 ViewToViewModelMapping?有什么明显的例子吗?
【解决方案2】:

一种可能性是在你的 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 中的某些属性。

如果你的主窗口中有多个视图模型,你可以这样写:

<views:YourUserControlName Test="{Binding SomeViewModel.SomeTextProperty}"/>
<views:YourUserControlName Test="{Binding SomeOtherViewModel.SomeTextProperty}"/>

【讨论】:

  • 谢谢,但我需要一个解决方案,留在 Catel 框架设计中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
相关资源
最近更新 更多