2016-07-30 33 views
1

Mein UWP muss eine Favoritenseite haben, die es dem Benutzer ermöglicht, die Daten auf der Seite neu anzuordnen und zu speichern. Ursprünglich stammen meine Daten aus einer großen JSON-Datei, die mit Jerson.net von Newtonsoft deserialisiert und für diese Seite in einem Dictionary gespeichert wird, das dann die öffentliche ObservableCollection füllt.Binden einer observierbaren Sammlung an eine GridView

Dies ist, wo ich jetzt verloren gehe, die ObservableCollection als DataContext festlegen und dann die Daten als eine Bindung im XAML-Code verwenden, um die GridView mit allen Titeln, Untertiteln und Bildern zu füllen, die jedes Element benötigt. In der Theorie sollte dies funktionieren, aber in meinen Versuchen und Tests bleibt die Seite leer, während der ganze C# Code hinter den Kulissen es so aussieht, als ob er aufgefüllt werden sollte.

Ich weiß nicht, warum die Seite nicht gefüllt ist. Ich wende mich an die kollektive Hilfe von euch allen.

S.S .: Ich sorge mich nicht wirklich um die Ordentlichkeit dieses Codes, ich will nur, dass es funktioniert.


XAML Datei

<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 Datei

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; } 
    } 
} 

Antwort

0

Ich fand es heraus. Mein Problem lag in der Art, wie ich die Daten an die Seite selbst weitergeben wollte. Anstatt DataContext = Items; zu verwenden und so auf die Daten zuzugreifen. Ich stelle stattdessen die direkte ItemsSource für die GridView.

Das Ergebnis Ende einfach veränderte DataContext = Items-itemGridView.ItemsSource = Items;

0

Ohne eine gute Minimal, Complete, and Verifiable code example ist es unmöglich zu wissen, was los ist. Allerdings ist eine eklatante Fehler im Code erscheint:

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

In XAML binden Sie {Binding Items}. Wenn DataContext auf den Eigenschaftswert Items festgelegt ist, wäre die korrekte Bindung tatsächlich nur {Binding}.

Alternativ, wenn Sie den XAML so behalten möchten, wie er ist, müssten Sie stattdessen setzen. Natürlich, wenn Sie es so gemacht haben, dann würden Sie auf das Problem stoßen, dass Sie nicht scheinen INotifyPropertyChanged.PropertyChanged zu erhöhen, oder sogar diese Schnittstelle zu implementieren. Sie können damit durchkommen, wenn Sie sicher sind, dass die Eigenschaft festgelegt wird, bevor die InitializeComponent()-Methode aufgerufen wird, aber in dem Code, den Sie angezeigt haben, scheint dies nicht der Fall zu sein.

Wenn Sie also die Bindung an {Binding Items} Sie auch INotifyPropertyChanged implementieren festlegen möchten und stellen Sie sicher, dass Sie das PropertyChanged Ereignis mit dem Eigenschaftsnamen erhöhen "Items", wenn Sie setzen tatsächlich die Eigenschaft.

Wenn das oben genannte nicht Ihre Frage behandelt, verbessern Sie bitte die Frage, indem Sie ein gutes MCVE zur Verfügung stellen, das das Problem zuverlässig reproduziert.

+0

Ich habe die Datacontext geändert nur '{Binding}' wie Sie vorgeschlagen, aber es hat nichts ändern (es sei denn, ich bin etwas fehlt). Ich möchte auch nicht die PropertyChanged Lösung implementieren, die Sie vorgeschlagen haben, da ich einfach nicht weiß, was es tut oder wie es funktioniert. Ich werde daran arbeiten, diese Frage so schnell wie möglich richtig zu sortieren. – Haybale100

+0

Wenn Sie WPF-Programme schreiben, müssen Sie ** etwas über 'INotifyPropertyChanged' lernen und in der Lage sein, es zu implementieren. Sie werden nicht in der Lage sein, nicht-triviale Bindungen zu erhalten, ohne dass es funktioniert. Was die aktuelle Frage angeht, kann ich nur Ratschläge geben, basierend auf dem, was Sie in Ihrer Frage gepostet haben. Wenn das Ändern der Bindung an 'ItemsSource =" {Binding} "das Problem nicht behoben hat, dann ist etwas anderes passiert, das in dem Code, den Sie gepostet haben, nicht offensichtlich ist. Wenn Sie die Frage so festlegen, dass sie ein gutes [mcve] enthält, wird sichergestellt, dass Sie eine Antwort erhalten, die sicher funktioniert. –