【问题标题】:Passing ModelData (context) between UserControls (views) MVVM Prism在 UserControls(视图)MVVM Prism 之间传递 ModelData(上下文)
【发布时间】:2018-07-18 23:55:02
【问题描述】:

我正在做一个项目,我有三个 ViewModel: ObjectDetailsViewMode 有一个 ObjectBase 类型的上下文(属性链接到一个模型); 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 是一个使用控件,它有一个用于编辑 Object.Name 的 TextBox、两个用于向 Object.Properties 添加新的 PropertyText/PropertyNumber 的按钮以及一个连接到该 Object.Properties 的 ItemsControl。

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

<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。我的问题是我需要将 Object.Properties 列表中的新属性传递给新创建的 View 的 ViewModel 并将其存储在我那里的 Context 属性中。

我无法避免为每种属性类型创建一个 View/ViewModel,因为某些属性类型(不是我在此处描述的类型)有一些底层逻辑。但我还有其他类型,如 Boolean、Reference、枚举...)

所以我真的需要向我尝试使用的 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 的自定义属性。我什至在 View 的后台代码中创建了一个 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);

这些都没有运气......我真的卡住了。

更简单的事情

如果 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));

我应该可以做到:

对吗?!为什么没有调用公共属性“Context”(我在那里放置了一个断点,但什么也没有得到)。

【问题讨论】:

  • 尝试将其设置为: 加上句号
  • @Unlockedluca 我试过了..但不起作用..当我创建实例时,ViewModel 中的 GET 方法被调用(不知道为什么)但 SET 方法没有://
  • 您的自定义上下文属性的类是否实现了 INotifyPropertyChanged?
  • @Unlockedluca 它实现了 BindableBase,它是 PRISM 中的一个基类,作为 INotifyPropertyChanged
  • 如果你添加例如它是否工作: 然后TextBlock 中显示的文本正确吗?

标签: c# wpf mvvm prism


【解决方案1】:

除了将视图的 Context 属性设置为新的 Binding 之外,还需要像这样分配当前的 DataContext

&lt;views:PropertyNumberView Context="{Binding .}"/&gt;

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

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

&lt;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>

【讨论】:

  • 但是 DataContext 应该指向 ViewModel 并且我正在传递对 Model 的引用......所以新的 ViewModel 知道它的上下文是什么。如果我明白你在说什么,那么我需要自己创建 ViewModel...
  • 哪个DataContext应该指向ViewModel,所以你要传递“Object”?
  • 如果您查看我的代码,我声明 ItemsControl 的 ItemsSource 链接到 Object.Properties(即 PropertyBase 的 ObservableCollection,这是一个模型而不是视图模型)......然后就像在 ListView 中一样需要将每个项目(PropertyBase)传递给新的 UserControler(PropertyTextView)(并在 ViewModel 中捕获它)......这样我就可以使用它了。
  • 啊,现在很清楚了,也许你应该在你的问题中包含这个,我会在几秒钟内更新我的答案
  • 我似乎无法让它工作...如果我为每个项目使用 DataTemplate 不会绑定引用 Object.Properties 中的相应属性...比如 Object.Properties [n]
【解决方案2】:

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

您没有在 Prism 中使用视图优先。如果您愿意,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; }
}

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

parentModel.WhateverProperty 将具有 NameValue 属性以及值的设置器,可能...

【讨论】:

  • 我的应用程序就像构建数据库的前视图...例如,您要创建一个名为“Persons”的新表,然后向其添加属性(相当于列),以便项目控制包含属性取决于选择的表和手动添加的属性。我很难做到这一点。我似乎不明白你的帮助
  • 我所说的只是一件事——直接创建您的视图模型,不要尝试使用自动创建的视图模型生成视图并在之后设置它们的上下文。创建时将上下文放入视图模型中。
  • 我想我明白你想说的话!不过有一个问题..我正在使用统一进行依赖注入...我想为此使用统一。如果我手动创建 ViewModel 并且他们需要一些 IDataAccess 接口,我不想在另一个与该组件无关的 ViewModel 中创建它。我该怎么做...有没有办法按需创建 ViewModel?!
  • 提示:抽象工厂。创建一个创建视图模型并注入它的类。然后您的父视图模型可以在没有new 的情况下随意创建子视图模型,并且子视图模型从工厂获取所有依赖项......请参阅:stackoverflow.com/questions/39768318/…
猜你喜欢
  • 2011-09-17
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
相关资源
最近更新 更多