簡體   English   中英

將Observable Collection綁定到GridView

[英]Binding an Observable Collection to a GridView

我的UWP需要有一個“收藏夾”頁面,允許用戶重新排序並保存頁面上的數據。 最初我的數據來自一個大型JSON文件,它使用Newtonsoft的Json.net進行反序列化,並在此字典中存儲在一個字典中,然后填充公共ObservableCollection。

這就是我現在迷失的地方,將ObservableCollection設置為DataContext,然后在XAML代碼中使用數據作為Binding,使用每個Item所需的所有標題,字幕和圖像填充GridView。 理論上這應該可以工作,但是在我的試驗和測試中,頁面仍然是空白的,而幕后的所有C#代碼似乎都應該填充它。

我不知道為什么頁面不適合我轉向你們所有人的集體幫助。

PS:我真的不關心這段代碼的整潔,我只是想讓它運轉起來。


XAML文件

<Page
x:Name="pageRoot"
x:Class="Melbourne_Getaway.FavouritesPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Melbourne_Getaway"
xmlns:data="using:Melbourne_Getaway.Data"
xmlns:common="using:Melbourne_Getaway.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Page.Resources>
    <x:String x:Key="AppName">Favourites</x:String>
</Page.Resources>

<!--
    This grid acts as a root panel for the page that defines two rows:
    * Row 0 contains the back button and page title
    * Row 1 contains the rest of the page layout
-->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ChildrenTransitions>
        <TransitionCollection>
            <EntranceThemeTransition />
        </TransitionCollection>
    </Grid.ChildrenTransitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="140" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <GridView
        x:Name="itemGridView"
        AutomationProperties.AutomationId="ItemsGridView"
        AutomationProperties.Name="Items"
        TabIndex="1"
        Grid.RowSpan="2"
        Padding="60,136,116,46"
        SelectionMode="None"
        IsSwipeEnabled="false"
        CanReorderItems="True"
        CanDragItems="True"
        AllowDrop="True"
        ItemsSource="{Binding Items}">
        <GridView.ItemTemplate>
            <DataTemplate>
                <Grid HorizontalAlignment="Left" Width="250" Height="107">
                    <Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}">
                        <Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" />
                    </Border>
                    <StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}">
                        <TextBlock Text="{Binding Title}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource BaseTextBlockStyle}" Height="30" Margin="15,0,15,0" FontWeight="SemiBold" />
                        <TextBlock Text="{Binding Group}" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource BaseTextBlockStyle}" TextWrapping="NoWrap" Margin="15,-15,15,10" FontSize="12" />
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </GridView.ItemTemplate>
    </GridView>

    <!-- Back button and page title -->
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="120" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                    Style="{StaticResource NavigationBackButtonNormalStyle}"
                    VerticalAlignment="Top"
                    AutomationProperties.Name="Back"
                    AutomationProperties.AutomationId="BackButton"
                    AutomationProperties.ItemType="Navigation Button" />
        <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1"
                    IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40" />
    </Grid>
</Grid>


CS檔案

using Melbourne_Getaway.Common;
using Melbourne_Getaway.Data;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Windows.Storage;
using Windows.UI.Popups;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Melbourne_Getaway
{
    public sealed partial class FavouritesPage : Page
    {
        public ObservableCollection<ItemData> Items { get; set; }

        private ObservableDictionary defaultViewModel = new ObservableDictionary();
        private NavigationHelper navigationHelper;
        private RootObject jsonLines;
        private StorageFile fileFavourites;
        private Dictionary<string, ItemData> ItemData = new Dictionary<string, ItemData>();

        public FavouritesPage()
        {
            loadJson();
            getFavFile();

            this.InitializeComponent();
            this.navigationHelper = new NavigationHelper(this);
            this.navigationHelper.LoadState += navigationHelper_LoadState;
        }

        private void setupObservableCollection()
        {
            Items = new ObservableCollection<ItemData>(ItemData.Values);
            DataContext = Items;
        }

        private async void loadJson()
        {
            var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///DataModel/SampleData.json"));
            string lines = await FileIO.ReadTextAsync(file);
            jsonLines = JsonConvert.DeserializeObject<RootObject>(lines);
            feedItems();
        }

        private async void getFavFile()
        {
            Windows.Storage.StorageFolder storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
            fileFavourites = await storageFolder.GetFileAsync("MelbGetaway.fav");
        }

        private async void feedItems()
        {
            if (await FileIO.ReadTextAsync(fileFavourites) != "")
            {
                foreach (var line in await FileIO.ReadLinesAsync(fileFavourites))
                {
                    foreach (var Group in jsonLines.Groups)
                    {
                        foreach (var Item in Group.Items)
                        {
                            if (Item.UniqueId == line)
                            {
                                var storage = new ItemData()
                                {
                                    Title = Item.Title,
                                    UniqueID = Item.UniqueId,
                                    ImagePath = Item.ImagePath,
                                    Group = Group.Title
                                };
                                ItemData.Add(storage.UniqueID, storage);
                            }
                        }
                    }
                }
            }
            else
            {//should only execute if favourites file is empty, first time use?
                foreach (var Group in jsonLines.Groups)
                {
                    foreach (var Item in Group.Items)
                    {
                        var storage = new ItemData()
                        {
                            Title = Item.Title,
                            UniqueID = Item.UniqueId,
                            ImagePath = Item.ImagePath,
                            Group = Group.Title
                        };
                        ItemData.Add(storage.UniqueID, storage);
                        await FileIO.AppendTextAsync(fileFavourites, Item.UniqueId + "\r\n");
                    }
                }
            }
            setupObservableCollection();
        }

        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }

        #region NavigationHelper loader

        public NavigationHelper NavigationHelper
        {
            get { return this.navigationHelper; }
        }

        private async void MessageBox(string Message)
        {
            MessageDialog dialog = new MessageDialog(Message);
            await dialog.ShowAsync();
        }

        private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
            var sampleDataGroups = await SampleDataSource.GetGroupsAsync();
            this.defaultViewModel["Groups"] = sampleDataGroups;
        }

        #endregion NavigationHelper loader

        #region NavigationHelper registration

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            navigationHelper.OnNavigatedFrom(e);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            navigationHelper.OnNavigatedTo(e);
        }

        #endregion NavigationHelper registration
    }

    public class ItemData
    {
        public string UniqueID { get; set; }
        public string Title { get; set; }
        public string Group { get; set; }
        public string ImagePath { get; set; }
    }
}

如果沒有一個好的Minimal,Complete和Verifiable代碼示例 ,就不可能確定是什么問題。 但是,您的代碼中會出現一個明顯的錯誤:

private void setupObservableCollection()
{
    Items = new ObservableCollection<ItemData>(ItemData.Values);
    DataContext = Items;
}

在您的XAML中,綁定到{Binding Items} DataContext設置為Items屬性值,正確的綁定實際上只是{Binding}

或者,如果你想保持XAML的方式,你必須設置DataContext = this; 代替。 當然,如果你這樣做,那么你會遇到一個問題,你似乎沒有提出INotifyPropertyChanged.PropertyChanged ,甚至實現該接口。 如果您確定在調用InitializeComponent()方法之前設置了屬性,那么您可以使用它,但在您顯示的代碼中似乎並非如此。

因此,如果要將綁定設置為{Binding Items} ,還需要實現INotifyPropertyChanged ,並確保在實際設置屬性時使用屬性名稱"Items"引發PropertyChanged事件。

如果上述問題無法解決您的問題,請通過提供可靠地再現問題的良好MCVE來改進問題。

我想到了。 我的問題在於我試圖將數據傳遞給頁面本身的方式。 而不是使用DataContext = Items; 並嘗試以這種方式訪問​​數據。 我改為為GridView設置直接的ItemsSource

最終結果只是將DataContext = Items更改為itemGridView.ItemsSource = Items;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM