在UserControls(视图)之间传递ModelData(上下文)MVVM Prism

时间:2018-02-08 12:02:35

标签: c# wpf mvvm prism

我在项目上工作并且我有三个ViewModel:ObjectDetailsViewMode有一个ObjectBase类型的Context(链接到模型的属性); PropertyTextViewModel具有PropertyText类型的Context,PropertyNumberViewModel具有PropertyNumber类型的Context。

以下是模型的结构:

public class ObjectBase : ModelBase
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set { SetProperty(ref _name, value); }
    }

    public DataCollection<PropertyBase> Properties { get; } = new DataCollection<PropertyBase>();
}

public class PropertyText : PropertyBase
{
    private string _default;
    public string Default
    {
        get { return _default; }
        set { SetProperty(ref _default, value); }
    }
}

public class PropertyNumber : PropertyBase
{
    private double _default = 0;
    public double Default
    {
        get { return _default; }
        set { SetProperty(ref _default, value); }
    }

    private double _minValue = 0;
    public double MinValue
    {
        get { return _minValue; }
        set { SetProperty(ref _minValue, value); }
    }

    private double _maxValue = 0;
    public double MaxValue
    {
        get { return _maxValue; }
        set { SetProperty(ref _maxValue, value); }
    }
}

关于视图,每个ViewModel都有一个视图。 ObjectDetailsView是一个use控件,它有一个用于编辑Object.Name的TextBox,两个用于向Object.Properties添加新PropertyText / PropertyNumber的按钮和一个连接到该Object.Properties的ItemsControl。

使用DataTemplate标记将ItemsControl(ItemsSource)中的每个PropertyBase解析为一个新视图:

<ItemsControl ItemsSource="{Binding Object.Properties}">
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type models:PropertyText}">
            <views:PropertyTextView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type models:PropertyNumber}">
            <views:PropertyNumberView />
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>

当我使用PRISM时,会自动为我创建正确的ViewModel,然后将视图DataContext设置为新的ViewModel。我的问题是我需要将新的Property从Object.Properties列表传递给新创建的View的ViewModel,并将其存储在我所拥有的Context属性中。

我无法避免为每种属性类型创建一个View / ViewModel,因为在某些Property类型上有一些底层逻辑(不是我在这里描述的那些..但我有其他类型,如Boolean,参考,枚举...)

所以我真的需要将值传递给我试图使用的ViewModel

<ItemsControl ItemsSource="{Binding Object.Properties}">
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type models:PropertyText}">
            <views:PropertyTextView Context="{Binding}"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type models:PropertyNumber}">
            <views:PropertyNumberView Context="{Binding}"/>
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>

请注意Context是我在ViewModel中创建的自定义属性,用于存储ModelContext。我甚至在视图后面的代码中创建了一个DependencyProperty:

    public PropertyBase Context
    {
        get { return (PropertyBase)GetValue(ContextProperty); }
        set { SetValue(ContextProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ContextProperty =
        DependencyProperty.Register("Context", typeof(PropertyBase), typeof(PropertyTextView), new PropertyMetadata(null));

但它并没有链接到ViewModels设置事件(我在那里做了一个断点而且......没有)。我甚至在PropertyTextView代码隐藏(构造函数)中尝试了一个SetBinding:

string propertyInViewModel = "Context";
var bindingViewMode = new Binding(propertyInViewModel) { Mode = BindingMode.TwoWay };
this.SetBinding(ContextProperty, bindingViewMode);

这些都没有运气......我&#39;真的卡住了。

更简单的事情

如果PropertyTextView具有此依赖项属性。

    public string Context
    {
        get { return (PropertyBase)GetValue(ContextProperty); }
        set { SetValue(ContextProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Context.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ContextProperty =
        DependencyProperty.Register("Context", typeof(string), typeof(PropertyTextBuilderView), new PropertyMetadata(null));

我应该可以这样做:

右?为什么不是公共财产&#34; Context&#34;没有被叫(我在那里放了一个断点而我什么都没得到。)

2 个答案:

答案 0 :(得分:0)

您不需要将视图的Context属性设置为新的Binding,而是需要像这样分配当前DataContext

<views:PropertyNumberView Context="{Binding .}"/>

这应该将当前Views.DataContext属性分配给您的新视图。

如果您在DataTemplate中,则可能需要指定RelativeSource

<views:PropertyNumberView Context="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}

<ItemsControl ItemsSource="{Binding Object.Properties}"> <ItemsControl.Resources> <DataTemplate DataType="{x:Type models:PropertyText}"> <views:PropertyTextView Context="{Binding .}"/> </DataTemplate> <ItemsControl.Resources> </ItemsControl>

答案 1 :(得分:0)

  

当我使用PRISM时,会自动为我创建正确的ViewModel

你没有 使用Prism的view-first。如果您选择ViewModelLocator可以提供帮助,但也可以查看模型优先。

如果我理解正确,您有一个视图模型,并希望使用子视图模型填充列表。就这样做:

internal class ParentViewModel : BindableBase
{
    public ParentViewModel( ParentModel parentModel, IChildViewModelFactory factory )
    {
        Children = new object[] { factory.CreateTextViewModel(parentModel.TextProperty), factory.CreateNumberViewModel(parentModel.NumberProperty) };
    }

    public IEnumerable Children { get; }
}

并通过DataTemplate s将不同的子视图模型映射到子视图。

parentModel.WhateverProperty会有NameValue属性以及值的设置者,可能......