我知道在WPF中,将自定义属性暴露给XAML的标准方式是将其定义为视图代码后台中的“DependencyProperty”。但这仅适用于如“UserControl”等“DependencyObject”。然而,在Prism框架中,我的代码后台(即从“UserControl”继承的类)为空,所有逻辑都在我的视图模型中处理,该视图模型从“BindableBase”派生,它不是“DependencyObject”的子类。请考虑以下XAML片段:
我对Prism还不太熟悉。我该如何暴露在我的MyCustomViewModel中定义的MyProperty,以便我可以在XAML中使用类似上面的标记来设置它?
<MyNamespace:MyCustomView MyProperty={Binding} />
MyCustomViewModel
的核心是什么。private string myProperty;
public string MyProperty {
get { return myProperty; }
set { SetProperty(ref myProperty, value); }
我对Prism还不太熟悉。我该如何暴露在我的MyCustomViewModel中定义的MyProperty,以便我可以在XAML中使用类似上面的标记来设置它?
更新
根据@mm8的答案和我们在相应评论中的讨论,我开发了一个最小(非)工作示例,展示我所想要的内容。首先是一个摘要:
- 数据模型是对象列表。
- Shell必须通过此对象类型的自定义用户控件来显示每个对象。
A) Shell
A.1) XAML
XAML很简单。
<Window x:Class="MyProject.Views.MainWindow"
Name="MainWindowName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:MyNamespace="clr-namespace:MyProject.Views"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="350" Width="525">
<ItemsControl ItemsSource="{Binding StringCollection, ElementName=MainWindowName}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<MyNamespace:MyUserControl MyTargetProperty="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
A.2) 代码后台
代码后台包含数据模型定义;实际上,我会将其定义在Models
命名空间中。
using System.Collections;
using System.Windows;
namespace MyProject.Views {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
StringCollection = new ArrayList();
StringCollection.Add("String 1");
StringCollection.Add("String 2");
StringCollection.Add("String 3");
}
private ArrayList stringCollection;
public ArrayList StringCollection {
get { return stringCollection; }
set { stringCollection = value; }
}
}
}
A.3) 视图模型
视图模型是Prism代码模板中提供的标准模板。
using Prism.Mvvm;
namespace MyProject.ViewModels {
public class MainWindowViewModel : BindableBase {
private string _title = "Prism Unity Application";
public string Title {
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainWindowViewModel() {
}
}
}
B) 自定义用户控件
这是一个有趣的部分。最终,我希望能够在MyUserControlViewModel
中访问MyTargetProperty
,因为我想在其上调用依赖于数据模型的其他工作的复杂程序逻辑,因此不能将其放置在代码后面。
B.1) XAML
非常简单; 只包含一个标签。
<UserControl x:Class="MyProject.Views.MyUserControl"
Name="UserControlName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Label Content="{Binding MyTargetProperty, ElementName=UserControlName}" Background="AliceBlue"/>
</UserControl>
B.2) 代码后置
这里我将目标属性声明为DependencyProperty
,正如@mm8的回答所建议的那样。
using System.Windows;
using System.Windows.Controls;
namespace MyProject.Views {
/// <summary>
/// Interaction logic for MyUserControl
/// </summary>
public partial class MyUserControl : UserControl {
public MyUserControl() {
InitializeComponent();
}
public static readonly DependencyProperty MyTargetPropertyProperty = DependencyProperty.Register("MyTargetProperty", typeof(string), typeof(MyUserControl));
public string MyTargetProperty {
get { return (string)GetValue(MyTargetPropertyProperty); }
set { SetValue(MyTargetPropertyProperty, value); }
}
}
}
B.3) 视图模型
视图模型定义了源属性。
using Prism.Mvvm;
namespace MyProject.ViewModels {
public class MyUserControlViewModel : BindableBase {
public MyUserControlViewModel() {
}
private string mySourceProperty;
public string MySourceProperty {
get { return mySourceProperty; }
set { SetProperty(ref mySourceProperty, value); }
}
}
}
我真的无法弄清楚如何访问我在MainWindow
的ItemTemplate
中设置的值,以及如何在MyUserControl
的视图模型中使用它们。
MyProperty={Binding}
起作用,MyProperty 必须是一个依赖属性。您必须在 UserControl 的代码后台中声明它,这没有任何问题。在 UserControl 中拥有“空代码后台”是毫无意义的。更一般地说,UserControl 不应该有任何“自己的”视图模型。相反,通常会将视图模型实例通过依赖属性值继承从其父元素(例如 Window)传递到 UserControl 的 DataContext 中。 - ClemensViewModelLocator.AutoWireViewModel="True"
会在内部将DataContext设置为每个View的单个ViewModel,但我认为在更一般的方法中,这并非必要。不过我还不确定如何将代码后台中的DependencyProperty与ViewModel的代码连接起来... - Informagic