当 ObservableCollection 中的项目发生更改时,ListView 不会更新

问题描述 投票:0回答:1

我目前正在尝试下载一个文件并在我的应用程序中的 ListView 中显示该文件。我对此有一个问题。 ObservableCollection 确实发生了变化,并且值也不同了。然而,ListView 不知道它发生了变化,并且从不更新 UI 以显示更改。

到目前为止我已经尝试过但不起作用:

  • 更改时使用 [ListView].UpdateLayout() 可观察集合;
  • 在 ViewModel 和定义中使用 INotifyPropertyChanged 对于 SoundBoardItem。

代码:

    public class SoundBoardItem : INotifyPropertyChanged
    {
        public string SoundName { get; set; }
    
        public string SoundLocation { get; set; }
        public string SoundLocationIcon { get; set; }
        public string SoundIconColor { get; set; }
        public string SoundIconVisible { get; set; }
        public string SoundIconTooltip { get; set; }
    
        public string SoundKeybindForecolor { get; set; }
        public string SoundKeybind { get; set; }
        public bool ProgressRingEnabled { get; set; }
        public bool ProgressRingIntermediate { get; set; }
        public int ProgressRingProgress { get; set; }
        public bool BtnEnabled { get; set; }
    
        public SoundBoardItem(string soundName, string soundLocation, string soundLocationIcon, bool soundIconVisible, string soundIconTooltip, string soundKeybind, bool progressRingEnabled, bool btnEnabled, bool progressRingIntermediate = true, int progressRingProgress = 100, string soundIconColor = null, string soundKeybindForecolor = null)
        {
        
            SoundName = soundName;
            SoundLocation = soundLocation;
            SoundLocationIcon = soundLocationIcon;
            SoundIconColor = soundIconColor;
            SoundIconTooltip = soundIconTooltip;
            SoundKeybindForecolor = soundKeybindForecolor;
            SoundKeybind = soundKeybind;
            ProgressRingEnabled = progressRingEnabled;
            ProgressRingIntermediate = progressRingIntermediate;
            ProgressRingProgress = progressRingProgress;
            BtnEnabled = btnEnabled;
            if (soundIconVisible == true) { SoundIconVisible = "Visible"; } else { SoundIconVisible = "Collapsed"; } // ease of use
        }

    public event PropertyChangedEventHandler PropertyChanged; // Also tried to use this in the ViewModel, but it didn't work either.
    public void OnPropertyChanged(string message)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(message));
        }
    }
}
public class SoundBoardItemViewmodel
{
    public ObservableCollection<SoundBoardItem> SoundBoardItems = new();
}

(内页)

private async void DownloadSoundFile(object sender, RoutedEventArgs e, string Name, string Url)
    {
        if (soundBoardItemViewmodel.SoundBoardItems.Any(x => x.SoundLocation == Url || x.SoundLocation == "Downloading... (" + Url + ")")) return;

        YoutubeClient youtube = new();

        StreamManifest streamManifest;
        IStreamInfo streamInfo;
        Stream audioOnlyStreamInfo;
        string CurrentName;

        var FilePath = AppDomain.CurrentDomain.BaseDirectory + "DownloadedSounds\\";

        if (!Directory.Exists(FilePath))
            Directory.CreateDirectory(FilePath);

        // print file path to debug output
        System.Diagnostics.Debug.WriteLine(FilePath);


        try
        {
            streamManifest = await youtube.Videos.Streams.GetManifestAsync(Url);
            streamInfo = streamManifest.GetAudioOnlyStreams().GetWithHighestBitrate();
            audioOnlyStreamInfo = await youtube.Videos.Streams.GetAsync(streamInfo);

            if (Name != "")
                CurrentName = Name;
            else
                CurrentName = (await youtube.Videos.GetAsync(Url)).Title;

            SoundBoardItem soundboardItem = new(CurrentName, "Downloading... (" + Url + ")", DownloadedFileIcon, false, "Downloaded File", "None", true, false, false, 0);
            soundBoardItemViewmodel.SoundBoardItems.Add(soundboardItem);

            var ProgressHandler = new Progress<double>(p => 
            { 
                soundboardItem.ProgressRingProgress = Convert.ToInt32(p * 100); // same here; Changes do not show up in UI.
                System.Diagnostics.Debug.WriteLine("Progress: " + Convert.ToInt32(p * 100) + "%"); 
            });

            await youtube.Videos.Streams.DownloadAsync(streamInfo, FilePath + $"video_DEBUG.{streamInfo.Container}", ProgressHandler);

            soundboardItem.ProgressRingIntermediate = true;
            soundboardItem.ProgressRingEnabled = false;
            soundboardItem.BtnEnabled = true;
            soundboardItem.SoundIconVisible = "Visible";
            soundboardItem.SoundLocation = Url; // Values get changed but the changes do not appear.
        }
        catch (Exception ex)
        {
            await ShellPage.g_AppMessageBox.ShowMessagebox("Download Error", "An error has occured while downloading the youtube video: " + Url + "\n\nPlease make sure that the URL is correct and links to a valid youtube video.\nPlease note that age restricted videos are not supported.\n\nException: " + ex.Message, "", "", "Okay", ContentDialogButton.Close);
            return;
        }



    }

(显示内存和 UI 差异的图像)

c# windows user-interface listview winui-3
1个回答
0
投票

展示了如何使用

INotifyPropertyChanged

但我建议您使用 CommunityToolkit.Mvvm NuGet 包。它带来了源生成器,可以为您创建

INotifyPropertyChanged
相关的样板代码。你的代码应该是这样的:

// The class needs to be `partial`.
public partial SoundBoardItem : ObservableProperty
{
    // The source generators will create a "SoundName" property 
    // implemented with INotifyPropertyChanged for you.    
    [ObservableProperty]
    private string _soundName;

    [ObservableProperty]
    private string _soundLocation;

    // The rest of your code here...
}
© www.soinside.com 2019 - 2024. All rights reserved.