我正在尝试设置一个 MVVM 风格的应用程序,我认为我在这些项目的交互方面陷入了一些困境,希望有人能提供帮助。我在这里做错了什么吗?
我想我的主要两个问题是
- 我应该如何从我的模型转向我的观点。目前我正在尝试通过转换器来做到这一点。
- 如果使用转换器是正确的,我该如何使其正常工作?我相信 Node 构造函数上设置的数据上下文已被包含转换器的 XAML 替换。
我的类(class)(稍微简化):
IFieldDescription
// Interface that is supposed to be the Model
public interface IFieldDescription
{
String Name { get; }
bool Disabled { get; }
}
节点模型
// Class that is supposed to be the ViewModel
public class NodeModel : NotifyPropertyChanged
{
internal NodeModel() { }
public NodeModel(IFieldDescription fieldDescription)
{
this.FieldDescription = fieldDescription;
}
protected IFieldDescription FieldDescription
{
get { return this.fieldDescription; }
set {
this.fieldDescription = value;
this.OnPropertyChanged("Name");
this.OnPropertyChanged("Disabled");
this.OnPropertyChanged("PrimaryKey"); }
}
private IFieldDescription fieldDescription;
public String Name { get { return this.FieldDescription.Name; } }
public Boolean Disabled { get { return this.FieldDescription.Disabled; } }
}
节点 代码隐藏
public Node(NodeModel model)
{
this.DataContext = model;
this.InitializeComponent();
}
XAML
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GO" x:Class="GO.Node" Background="White"
>
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <!-- Primary Key Icon -->
<ColumnDefinition Width="Auto"/> <!-- Type Icon -->
<ColumnDefinition/> <!-- Node Text -->
<ColumnDefinition Width="Auto"/> <!-- Option Cog -->
<ColumnDefinition Width="Auto"/> <!-- Match Icon -->
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<local:AttributeDataTypeConverter x:Key="DateTypeConverter"/>
</Grid.Resources>
<Image Grid.Column="0" Source="C:\Users\ian.wright\Documents\Expression\Blend 4\Projects\GO\GO\Resources\Images\PrimaryKey.png" Stretch="None" Visibility="{Binding Path=IsPrimaryKey}"/>
<Image Grid.Column="1" Source="{Binding Path=Type, Converter={StaticResource DateTypeConverter}}" Stretch="None"/>
<TextBlock Grid.Column="2" Text="{Binding Path=Name}" VerticalAlignment="Bottom" Margin="0,0,0,2"/>
<Image Grid.Column="3" Source="C:\Users\ian.wright\Documents\Expression\Blend 4\Projects\GO\GO\Resources\Images\Cog.png" Stretch="None" Visibility="{Binding Path=HasOptions}"/>
<Image Grid.Column="4" Source="{Binding Path=CastType}" Stretch="None"/>
</Grid>
</UserControl>
主窗口
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="GO.MainWindow"
xmlns:local="clr-namespace:GO"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid Width="200" Height="500">
<Grid.Resources>
<local:NodeConverter x:Key="NodeConverter"/>
<local:ModelToViewConverter x:Key="ModelConverter"/>
</Grid.Resources>
<!--<ListView Grid.Column="1" ItemsSource="{Binding Path=FieldDescriptions, Converter={StaticResource ModelConverter}}">-->
<ListView Grid.Column="1" ItemsSource="{Binding Path=FieldDescriptions}">
<ListView.ItemTemplate>
<DataTemplate>
<local:Node DataContext="{Binding Converter={StaticResource ModelConverter}}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
主窗口的数据上下文设置为新的 RD(),其定义如下: 研发
public class RD
{
private IEnumerable<IFieldDescription> GetTestData()
{
yield return new FieldDescription("String", true);
yield return new FieldDescription("Integer", false);
yield return new FieldDescription("Double", false);
yield return new FieldDescription("Date", false);
yield return new FieldDescription("Enum", false);
}
public virtual ObservableCollection<IFieldDescription> FieldDescriptions
{
get { return new ObservableCollection<IFieldDescription>(GetTestData()); }
}
}
我的任何转换器当前定义为:
public class ModelToViewConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
if (value is IFieldDescription)
{
NodeModel model = new NodeModel((IFieldDescription)value);
return new Node(model);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
最佳答案
通常我使用DataTemplates
用于绑 View
与 Model
或ViewModel
我的 View 的代码隐藏引用 Model 或 ViewModel 的唯一地方是在启动时,它将启动 ViewModel 设置为启动 View 的 DataContext
。其他一切都与 DataTemplates
连接。 (或 DataTemplateSelectors
对于 Silverlight)。
(实际上,公平地说,有时我确实需要做一些特殊的事情,我会将对象的 DataContext
转换为代码隐藏中的 ViewModel 或 Model,但这种情况很少见,我将它们视为黑客)
例如设置启动View/ViewModel:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var app = new ShellView();
var context = new ShellViewModel();
app.DataContext = context;
app.Show();
}
}
以下是一些数据模板的示例:
<Window.Resources>
<DataTemplate DataType="{x:Type local:SomeViewModel}">
<local:SomeViewForViewModel />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SomeModel}">
<local:SomeViewForModel />
</DataTemplate>
</Window.Resources>
最后,我将使用 ContentControls
在我想要显示 View 的 XAML 中
<ContentControl Content="{Binding SomeViewModelProperty}" />
或
<ContentControl Content="{Binding SomeModelProperty}" />
有时甚至不需要 ContentControl。例如,如果您绑定(bind)了 ListView
到ObservableCollection<NodeModel>
,然后 ListView
中的每一项将是 NodeModel
类型的对象WPF 将自动为此选择 DataTemplate。
<ListView ItemsSource="{Binding Path=CollectionOfNodeModel}">
<ListView.Resources> <!-- Could also put this in Window.Resources -->
<DataTemplate DataType="{x:Type local:NodeModel}">
<local:Node /> <!-- DataContext will implicitly be the NodeModel object -->
</DataTemplate>
</ListView.Resources>
</ListView>
MVVM 背后的想法是,整个应用程序在 ViewModel 中运行,而 View 只是一个漂亮的 UI,位于 ViewModel 之上,使它们更加用户友好。在完美的世界中, View 可以轻松地被任何其他 UI 替换
如果你有兴趣,我有一个simple MVVM example在我的博客上,其中包含一些使用 MVVM 设计模式的示例
关于c# - 如何最好地应用WPF MVVM?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9330920/