在尝试基于ListView中的项目创建新窗口时,是否正确使用MVVM



所以我目前正在玩WPF和MVVM,我一直在尝试找到一种方法来选择列表中的项目并将其显示在新窗口中。我提出了一个我个人喜欢的解决方案,但我不确定它是否遵循有效的MVVM架构。

所以我有我的MainWindow.xaml

<Window x:Class="Views.MainWindow"
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:Views" 
xmlns:viewmodel="clr-namespace:Views.MVVM.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
Background="#252525">
<Window.DataContext>
<viewmodel:MainViewModel/>
</Window.DataContext>
<StackPanel Orientation="Horizontal">
<ListView ItemsSource="{Binding NetworkObjects}"
Style="{StaticResource ListStyle}"
Name="MainList"/>
</StackPanel>
</Window>

它使用这种绑定集合中每个项的样式,还应用了一个MouseBinding,它允许我LeftDoubleClick该项以调用命令。我将整个对象作为命令参数传递,因为这是DataContext。这是新窗口所需要的。

<Style TargetType="ListView" x:Key="ListStyle">
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel Margin="2">
<DockPanel.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" 
Command="{Binding DisplayItemCommand}"
CommandParameter="{Binding Path=.}"/>
</DockPanel.InputBindings>
<DockPanel.Style>
<Style TargetType="DockPanel">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#303030"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}}, 
Path=IsSelected}" Value="True">
<Setter Property="Background" Value="MediumSpringGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DockPanel.Style>
<TextBlock Text="{Binding NetworkModel.Address}" Foreground="Black"/>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

MainViewModel什么也不做,只是在构造函数中生成一些伪数据。这就是我开始怀疑这是否是有效的MVVM的地方,因为我生成的对象不是基于Model,而是基于整个ViewModel,这在理论上是有意义的,但我不确定。

public ObservableCollection<NetworkObjectViewModel> NetworkObjects { get; set; }
public MainViewModel()
{
NetworkObjects = new ObservableCollection<NetworkObjectViewModel>();
for (int i = 0; i < 10; i++)
{
NetworkObjects.Add(new NetworkObjectViewModel() { NetworkModel = new NetworkModel { Address = $"Address {i}", Port = i } });
}
}

并且CCD_ 8包含CCD_ 9和CCD_。

public class NetworkObjectViewModel
{
public NetworkModel NetworkModel { get; set; }
public RelayCommand DisplayItemCommand { get; set; }
public NetworkObjectViewModel()
{
DisplayItemCommand = new RelayCommand(o =>
{
WindowService.ShowWindow(o);
});
}
}

WindowService很简单,它只是创建一个新的GenericWindow并将其设置为DataContext,这样它就可以根据DataContext做出决定并显示正确的UserControl

internal class WindowService
{
public static void ShowWindow(object DataCtx)
{
var t  = new GenericWindow();
t.DataContext = DataCtx;
t.Show();
}
}

这是GenericWindow.xaml

<Window.Resources>
<DataTemplate DataType="{x:Type vms:NetworkObjectViewModel}">
<v:TestView/>
</DataTemplate>

<DataTemplate DataType="{x:Type vms:NetworkObjectViewModel2}">
<v:TestView2/>
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding .}" />

TestView.xaml,它只是一个简单的UserControl,看起来像这个

<Grid>
<TextBox Text="{Binding NetworkModel.Address, UpdateSourceTrigger=PropertyChanged}"
Width="100"
Height="25"
IsEnabled="True"/>
</Grid>

这就是我开始怀疑这是否是有效的MVVM的地方,因为我生成的对象不是基于模型,而是基于整个ViewModel,这在理论上是有意义的,但我不确定。

这很有道理。

MVVM中的模型通常指的是不想直接绑定的类型,例如数据传输对象(DTO(、包含业务逻辑甚至服务或存储库的域对象。

创建并公开";"孩子";要从"视图"绑定到的视图模型;"父";视图模型类是一种非常好的常用方法。

最新更新