英文:
Nested CollectionView or Displaying nested data inside of a collection view
问题
I am trying to avoid bad practice by NOT adding a Collection View inside of a Collection view to display nested data and I have a class of
public partial class Items
{
public int itemNumber { get; set; }
public string itemdescr { get; set; }
public List<Items> Child { get; set; }
}
my collection view looks as such
<CollectionView x:Name="CollectionViewBoM" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" ItemsSource="{Binding Data}">
<CollectionView.ItemTemplate>
<DataTemplate>
<mct:Expander>
<mct:Expander.Header>
<Grid HeightRequest="45" MaximumHeightRequest="90" ColumnSpacing="1" RowSpacing="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" Style="{DynamicResource ContentBoxView}"/>
<BoxView Grid.Column="1" Style="{DynamicResource ContentBoxView}"/>
<Label TextColor="{DynamicResource SecondaryTextColor}" Grid.Column="0" Text="{Binding itemNumber}" Style="{DynamicResource ContentLabel}"/>
<Label TextColor="{DynamicResource SecondaryTextColor}" Grid.Column="1" Text="{Binding Description}" Style="{DynamicResource ContentLabel}"/>
</Grid>
</mct:Expander.Header>
<mct:Expander.Content x:Name="CollectionViewChild">
<StackLayout BindableLayout.ItemsSource="{Binding Child}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<HorizontalStackLayout>
<Label Text="{Binding itemNumber}" />
<Label Text="{Binding itemdescr}" Margin="10,0,0,0"/>
</HorizontalStackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</mct:Expander.Content>
</mct:Expander>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I am binding to the view model as such but I am able to see the Data but not able to see the Child data. Am I incorrectly using the BindableLayout.ItemsSource?
[ObservableProperty]
public List<Items> data;
英文:
I am trying to avoid bad practice by NOT adding a Collection View inside of a Collection view to display nested data and I have a class of
public partial class Items
{
public int itemNumber { get; set; }
public string itemdescr{ get; set; }
public List<Items> Child { get; set; }
}
my collection view looks as such
<CollectionView x:Name="CollectionViewBoM" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" ItemsSource="{Binding Data}">
<CollectionView.ItemTemplate>
<DataTemplate >
<mct:Expander >
<mct:Expander.Header>
<Grid HeightRequest="45" MaximumHeightRequest="90" ColumnSpacing="1" RowSpacing="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" Style="{DynamicResource ContentBoxView}"/>
<BoxView Grid.Column="1" Style="{DynamicResource ContentBoxView}"/>
<Label TextColor="{DynamicResource SecondaryTextColor}" Grid.Column="0" Text="{Binding itemNumber}" Style="{DynamicResource ContentLabel}"/>
<Label TextColor="{DynamicResource SecondaryTextColor}" Grid.Column="1" Text="{Binding Description}" Style="{DynamicResource ContentLabel}"/>
</Grid>
</mct:Expander.Header>
<mct:Expander.Content x:Name="CollectionViewChild">
<StackLayout BindableLayout.ItemsSource="{Binding Child}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<HorizontalStackLayout>
<Label Text="{Binding itemNumber}" />
<Label Text="{Binding itemdescr}" Margin="10,0,0,0"/>
</HorizontalStackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</mct:Expander.Content>
</mct:Expander>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I am binding to the view model as such but I am able to see the Data but not able to see the Child data. Am I incorrectly using the BindableLayout.ItemsSource?
[ObservableProperty]
public List<Items> data;
答案1
得分: 2
你可以重新检查是否正确获取了内部列表数据(Child
)。
根据你的代码,我制作了一个演示来实现这个功能,它可以正常工作。
你可以参考以下代码:
public partial class MyViewModel : ObservableObject
{
[ObservableProperty]
public List<Items> Data;
public MyViewModel()
{
List<Items> Childs = new List<Items>();
Childs.Add(new Items { itemNumber = 01 - 1, itemdescr = "desc-01-1" });
Childs.Add(new Items { itemNumber = 02 - 1, itemdescr = "desc-02-1" });
Childs.Add(new Items { itemNumber = 03 - 1, itemdescr = "desc-03-1" });
Data = new List<Items>();
Data.Add(new Items { itemNumber = 01, itemdescr = "desc-01", Child = Childs });
Data.Add(new Items { itemNumber = 02, itemdescr = "desc-02", Child = Childs });
Data.Add(new Items { itemNumber = 03, itemdescr = "desc-03", Child = Childs });
Data.Add(new Items { itemNumber = 04, itemdescr = "desc-04", Child = Childs });
Data.Add(new Items { itemNumber = 05, itemdescr = "desc-05", Child = Childs });
Data.Add(new Items { itemNumber = 06, itemdescr = "desc-06", Child = Childs });
}
}
用法:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiMVVMToolkitApp.MyPage"
xmlns:viewmodel="clr-namespace:MauiMVVMToolkitApp.ViewModels"
xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
Title="MyPage">
<ContentPage.BindingContext>
<viewmodel:MyViewModel></viewmodel:MyViewModel>
</ContentPage.BindingContext>
<VerticalStackLayout>
<CollectionView x:Name="CollectionViewBoM" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" ItemsSource="{Binding Data}">
<CollectionView.ItemTemplate>
<DataTemplate>
<mct:Expander>
<mct:Expander.Header>
<Grid HeightRequest="45" MaximumHeightRequest="90" ColumnSpacing="1" RowSpacing="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--
<BoxView Grid.Column="0" />
<BoxView Grid.Column="1" />
-->
<Label Grid.Column="0" Text="{Binding itemNumber}" />
<Label Grid.Column="1" Text="{Binding Description}" />
</Grid>
</mct:Expander.Header>
<mct:Expander.Content x:Name="CollectionViewChild">
<StackLayout BindableLayout.ItemsSource="{Binding Child}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<HorizontalStackLayout>
<Label Text="{Binding itemNumber}" />
<Label Text="{Binding itemdescr}" Margin="10,0,0,0"/>
</HorizontalStackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</mct:Expander.Content>
</mct:Expander>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</ContentPage>
注意:
为了简化代码,我注释掉了布局中的两个 BoxView
。
另外,我注意到类 Items
还应该包含另一个属性 Description
,而类 Items
的属性(Child)的内部子元素也应该是类型为 Items
。在初始化数据时请注意这一点。
英文:
You can recheck if you could get the inner list data(Child
) correctly.
Based on your code, I made a demo to achieve this functionality, and it could work properly.
You can refer to the following code:
public partial class MyViewModel:ObservableObject
{
[ObservableProperty]
public List<Items> data;
public MyViewModel()
{
List<Items> Childs = new List<Items>();
Childs.Add(new Items { itemNumber = 01 - 1, itemdescr = "desc-01-1" });
Childs.Add(new Items { itemNumber = 02 - 1, itemdescr = "desc-02-1" });
Childs.Add(new Items { itemNumber = 03 - 1, itemdescr = "desc-03-1" });
Data = new List<Items>();
Data.Add(new Items { itemNumber= 01, itemdescr ="desc-01",Child= Childs });
Data.Add(new Items { itemNumber= 02, itemdescr ="desc-02", Child = Childs });
Data.Add(new Items { itemNumber= 03, itemdescr ="desc-03", Child = Childs });
Data.Add(new Items { itemNumber= 04, itemdescr ="desc-04" , Child = Childs });
Data.Add(new Items { itemNumber= 05, itemdescr ="desc-05" , Child = Childs });
Data.Add(new Items { itemNumber= 06, itemdescr ="desc-06" , Child = Childs });
}
}
Usage:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiMVVMToolkitApp.MyPage"
xmlns:viewmodel="clr-namespace:MauiMVVMToolkitApp.ViewModels"
xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
Title="MyPage">
<ContentPage.BindingContext>
<viewmodel:MyViewModel></viewmodel:MyViewModel>
</ContentPage.BindingContext>
<VerticalStackLayout>
<CollectionView x:Name="CollectionViewBoM" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" ItemsSource="{Binding Data}">
<CollectionView.ItemTemplate>
<DataTemplate >
<mct:Expander >
<mct:Expander.Header>
<Grid HeightRequest="45" MaximumHeightRequest="90" ColumnSpacing="1" RowSpacing="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--<BoxView Grid.Column="0" />
<BoxView Grid.Column="1" />-->
<Label Grid.Column="0" Text="{Binding itemNumber}" />
<Label Grid.Column="1" Text="{Binding Description}" />
</Grid>
</mct:Expander.Header>
<mct:Expander.Content x:Name="CollectionViewChild">
<StackLayout BindableLayout.ItemsSource="{Binding Child}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<HorizontalStackLayout>
<Label Text="{Binding itemNumber}" />
<Label Text="{Binding itemdescr}" Margin="10,0,0,0"/>
</HorizontalStackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</mct:Expander.Content>
</mct:Expander>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</ContentPage>
Note:
For the sake of code brevity, I commented out the two BoxView
of the layout.
Besides, I noticed that the class Items
should also contain another attribute Description
, and that the property of the Class Items
(Child), whose internal child elements are also of type Items
. Please pay attention to this when initializing the data.
答案2
得分: 0
以下是您要翻译的内容:
首先,我进行了以下名称更改:
- Items -> Item
- itemNumber -> ItemNumber
- itemDescr -> ItemDesc
- Child -> Children
- 将Item变成了一个视图模型,使其继承ObservableObject
- 将Children变成了ObservableCollection<Item>
然后,在我的MainViewModel.cs中,我不仅声明了ObservableCollection,还实现了一个SelectedItem。
接下来,对于UI,我声明了两个CollectionView,一个用于Master,一个用于Detail。在第一个CollectionView中,我对SelectedItem进行了双向数据绑定(请注意,您还需要设置SelectionMode="Single")。在第二个CollectionView中,相同的SelectedItem被用作绑定上下文,以便我可以访问Children。最后,减少XAML复杂性的另一种方法是将DataTemplates放入Resources中,并稍后引用它们的键名。
您应该注意,CollectionView并不是嵌套的,而是按顺序声明的,因此,您可以简单地控制它们的放置。我使用了一个简单的VerticalStackLayout,但您可以使用Grid按您的需求排列它们。
如果您不希望在SelectedItem上进行双向绑定,您可以创建导航命令,例如First、Previous、Next、Last,并以此方式更新SelectedItem。
英文:
Firstly, I did the following name changes:
- Items -> Item
- itemNumber -> ItemNumber
- itemDescr -> ItemDesc
- Child -> Children
- Turned Item into a view model by making it inherit ObservableObject
- Made Children an ObservableCollection<Item>
public partial class Item : ObservableObject
{
[ObservableProperty]
private int _itemNumber;
[ObservableProperty]
private string _itemDesc;
[ObservableProperty]
private ObservableCollection<Item> _children = new ObservableCollection<Item>();
}
Then, in my MainViewModel.cs I declare not only the ObservableCollection, but, I also implement a SelectedItem.
public partial class MainViewModel: ObservableObject
{
[ObservableProperty]
private ObservableCollection<Item> _items = new ObservableCollection<Item>();
[ObservableProperty]
private Item? _selectedItem;
public MainViewModel()
{
Item item;
item = new Item() { ItemNumber = 101, ItemDesc = "Parent Item 101" };
item.Children.Add(new Item() { ItemNumber = 1001, ItemDesc = "Child Item 1001" });
item.Children.Add(new Item() { ItemNumber = 1002, ItemDesc = "Child Item 1002" });
Items.Add(item);
item = new Item() { ItemNumber = 201, ItemDesc = "Parent Item 201" };
item.Children.Add(new Item() { ItemNumber = 2001, ItemDesc = "Child Item 2001" });
item.Children.Add(new Item() { ItemNumber = 2002, ItemDesc = "Child Item 2002" });
item.Children.Add(new Item() { ItemNumber = 2003, ItemDesc = "Child Item 2003" });
Items.Add(item);
SelectedItem = Items[0];
}
}
Then, for UI I declared two CollectionViews one for Master and one for Detail. In the first CollectionView I do a TwoWay data binding on the SelectedItem (note you also need to set SelectionMode="Single"). In the second CollectionView the same SelectedItem is used as a binding context so that I can access the Children. Lastly, another way to reduce the complexity of your XAML is to put your DataTemplates in Resources and refer to their key names later.
You should note that the CollectionViews are not nested but declared sequentially, so, it should be simple for you to control their placement. I've used a simple VerticalStackLayout, but you can space them how you want with Grid.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="maui_mvvm_sample.MainPage">
<ContentPage.Resources>
<DataTemplate x:Key="parentTemplate">
<HorizontalStackLayout>
<Label Text="{Binding ItemNumber}"/>
<Label Text="{Binding ItemDesc}"/>
</HorizontalStackLayout>
</DataTemplate>
<DataTemplate x:Key="childTemplate">
<HorizontalStackLayout>
<Label Text="{Binding ItemNumber}"/>
<Label Text="{Binding ItemDesc}"/>
</HorizontalStackLayout>
</DataTemplate>
</ContentPage.Resources>
<VerticalStackLayout>
<Label Text="Master"/>
<CollectionView ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource parentTemplate}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
SelectionMode="Single"/>
<Label Text="Detail"/>
<CollectionView BindingContext="{Binding SelectedItem}"
ItemsSource="{Binding Children}"
ItemTemplate="{StaticResource childTemplate}">
</CollectionView>
</VerticalStackLayout>
</ContentPage>
If you do not wish to do a TwoWay binding on SelectedItem you can create navigation commands such as First, Previous, Next, Last, and update SelectedItem that way.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论