【发布时间】:2021-11-01 16:36:04
【问题描述】:
我正在尝试创建一个向我显示组列表的 WPF MVVM 应用程序。该示例保持非常简单,对于所描述的情况,它可能太复杂了。为此,我创建了三个 UserControl:
- SideMenuControl(应该显示一个文本框和组列表)
- GroupListControl(应包含单个组)
- GroupControl(应该显示组的名称)
应该是这样的:
________________________
| SideMenuControl |
| |
| Hello World |
| ____________________ |
| |GroupListControl | |
| | | |
| | ________________ | |
| | | Group1 | | |
| | | Group2 | | |
| | |________________| | |
| |____________________| |
|________________________|
但是,我不明白如何将 ObservableCollection Groups 传递给 GroupListControl。我想它必须通过 DataContext、Content 和/或 ItemSource 成功。谁能进一步帮助我?
GroupControl.xaml
<UserControl x:Class="WpfApp1.GroupControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="300">
<TextBlock Grid.Column="1" Text="{Binding Name}" VerticalAlignment="Center"/>
</UserControl>
GroupListControl.xaml
<UserControl x:Class="WpfApp1.GroupListControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Groups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:GroupControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</UserControl>
SideMenuControl.xaml
<UserControl x:Class="WpfApp1.SideMenuControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="Hello World"/>
<ContentPresenter Grid.Row="1"/>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
GroupViewModel.cs
using Microsoft.Toolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
namespace WpfApp1
{
public class GroupViewModel : ObservableObject
{
private Group _group;
public string Name
{
get => _group.Name;
set => SetProperty(_group.Name, value, _group, (model, name) => model.Name = name);
}
public GroupViewModel(Group model)
{
_group = model;
}
}
}
GroupCollectionViewModel.cs
using Microsoft.Toolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
namespace WpfApp1
{
public class GroupCollectionViewModel : ObservableObject
{
public ObservableCollection<GroupViewModel> Groups { get; set; }
public GroupCollectionViewModel()
{
Groups = new ObservableCollection<GroupViewModel>();
Groups.Add(new GroupViewModel(new Group { Name = "Group1" }));
Groups.Add(new GroupViewModel(new Group { Name = "Group2" }));
}
}
}
MainWindow.xaml
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="GroupList" Height="450" Width="800">
<local:SideMenuControl
DataContext="{Binding Groups}">
</local:SideMenuControl>
</Window>
MainWindow.xaml.cs
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new GroupCollectionViewModel();
}
}
}
编辑
如果我用 GroupListControl.xaml 中的 ScrollViewer 元素替换 ContentPresenter 元素(并删除单词 Groups 来自 SideMenuControl.xaml 中的绑定元素),如下所示,我得到了我想要的结果。但是如何使用 UserControls(GroupListControl 和 GroupControl)实现这一点?
SideMenuControl.xaml(修改)
<UserControl x:Class="WpfApp1.SideMenuControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="Hello World"/>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:GroupControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
【问题讨论】:
-
如果不查看您实际在哪里实例化 GroupListControl,您的问题很难理解。我也不明白你的文件命名,例如。 “GroupListControl.cs”,其中文件是 xaml 模板,而不是 cs 代码 - 应该是 GroupListControl.xaml?您可以在 GroupListControl.cs 的视图模型中放置一个 ObservableCollection 并在初始化 GroupListControl 时将数据放入其中吗?
-
感谢您的建议,我已经更正了文件名。 GroupListControl 没有直接实例化,也许这就是问题所在。我不知道这应该在哪里完成。我在 GroupCollectionViewModel 中有一个 ObservableCollection,所以我不明白你的建议。
-
我的意思是:在您共享的代码中,您从未真正使用过 GroupListControl。 Usercontrol 没有放置在任何 XAML 模板中(这也将实例化它。)我也对此感到困惑:
public ObservableCollection<GroupViewModel> Groups { get; set; }GroupViewModel 根据名称应该是一个 ViewModel,但您似乎只是在使用它作为您的组数据的容器,与任何视图无关。命名背后有什么原因吗?如果您使用视图的 ViewModel(例如GroupListControl类),您的问题应该是微不足道的 :) -
ObservableCollection Groups 已绑定 MainWindow.xaml:
。我想我需要在此 SideMenuControl 元素中将 ContentTemplate 添加到 GroupListControl。但到目前为止,我还没有成功。 -
从哪里传过来的?你的问题到底是什么?你能把它缩小一点吗?你不会“传递”任何东西给
UserControl。