Reputation: 63
I'm trying to use WinUI 3's ItemsRepeater
class to display a row for each chapter's title in an MP3 file (this will later be updated so that each row displays a text box to edit timestamps, but for now, just the basics since I'm new to WinUI 3).
I am using a library to pull the chapter frames into a list correctly (the list is populated with 9 values for a sample MP3 file), so I know the variable ChapterItems is correctly populated, but only my initial value of "Hello Governor" shows in the app.
Here is the XAML code:
<!-- Licensed under the MIT License. -->
<Window
x:Class="ChapEdit.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ChapEdit"
xmlns:atl="using:ATL"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="AppTitleBar">
<Image Source="Images/WindowIcon.png"
HorizontalAlignment="Left"
Width="16" Height="16"
Margin="8,0"/>
<TextBlock x:Name="AppTitleTextBlock" Text="Audio Chapter Editor"
TextWrapping="NoWrap"
Style="{StaticResource CaptionTextBlockStyle}"
VerticalAlignment="Center"
Margin="28,0,0,0"/>
</Grid>
<StackPanel Grid.Row="1" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="PickAFileButton" Content="Select an audio file with chapter markers"
Click="PickAFileButton_Click" Margin="0,0,0,10"/>
<!--<RichTextBlock x:Name="TimestampDisplayTextbox"></RichTextBlock>-->
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
IsVerticalScrollChainingEnabled="true"
MaxHeight="500"
MaxWidth="500">
<ItemsRepeater
ItemsSource="{x:Bind ChapterItems, Mode=OneWay}">
<ItemsRepeater.Layout>
<StackLayout Orientation="Vertical" Spacing="8"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="atl:ChapterInfo">
<TextBlock Text="{x:Bind Title}" />
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>
</StackPanel>
</Grid>
</Window>
And here is the C# app window code:
// Licensed under the MIT License.
using ATL;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Documents;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage.Pickers;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace ChapEdit
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
private ObservableCollection<ChapterInfo> ChapterItems;
public MainWindow() {
this.InitializeComponent();
this.ExtendsContentIntoTitleBar = true;
SetTitleBar(AppTitleBar);
ChapterItems = new ObservableCollection<ChapterInfo>();
ChapterItems.Add(new ChapterInfo(startTime: 1500, title: "Hello Governor"));
}
private async void PickAFileButton_Click(object sender, RoutedEventArgs e) {
// Clear previous returned file name, if it exists, between iterations of this scenario
PickAFileButton.Content = "Select an audio file with chapters";
//TimestampDisplayTextbox.Blocks.Clear();
// Create a file picker
var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
// Retrieve the window handle (HWND) of the current WinUI 3 window.
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
// Initialize the file picker with the window handle (HWND).
WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);
// Set options for your file picker
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.FileTypeFilter.Add(".mp3");
openPicker.FileTypeFilter.Add(".m4a");
// Open the picker for the user to pick a file
var file = await openPicker.PickSingleFileAsync();
if (file != null) {
PickAFileButton.Content = file.Name;
var audioMeta = new AudioTagParser(file);
ChapterItems = audioMeta.GetChaptersAsObservableCollection();
} else {
PickAFileButton.Content = "Select an audio file with chapters";
}
}
}
}
Any ideas? I've tried setting the mode to OneWay to try to get it to update the UI when ChapterItems is updated, but to no avail.
Upvotes: 0
Views: 1082
Reputation: 13666
If you are not interested in doing this the MVVM way and do this in code-behind(*.xaml.cs), you don't need binding.
You can just name your ItemsRepeater
:
<ItemsRepeater x:Name="ChapterItemsItemsRepeater" .../>
and set ItemsSource
directly:
this.ChapterItemsItemsRepeater.ItemsSource = audioMeta.GetChaptersAsObservableCollection();
Upvotes: 1
Reputation: 5042
Instead of:
ChapterItems = audioMeta.GetChaptersAsObservableCollection();
try
ChapterItems.Clear;
ChapterItems.AddRange(audioMeta.GetChaptersAsObservableCollection());
The problem with your original code is that you replace the collection. Since ChapterItem
is just a normal property, without notification mechanisms, binding does not work, and your ItemSource is bound to the original collection that you create in the constructor. That is why you should modify the collection, not replace it.
Upvotes: 1