diff --git a/Ryujinx.Ava/Assets/Locales/en_US.json b/Ryujinx.Ava/Assets/Locales/en_US.json
index 24f44deeb2..ba5af264ba 100644
--- a/Ryujinx.Ava/Assets/Locales/en_US.json
+++ b/Ryujinx.Ava/Assets/Locales/en_US.json
@@ -524,7 +524,7 @@
   "UserErrorUndefinedDescription": "An undefined error occured! This shouldn't happen, please contact a dev!",
   "OpenSetupGuideMessage": "Open the Setup Guide",
   "NoUpdate": "No Update",
-  "TitleUpdateVersionLabel": "Version {0} - {1}",
+  "TitleUpdateVersionLabel": "Version {0}",
   "RyujinxInfo": "Ryujinx - Info",
   "RyujinxConfirm": "Ryujinx - Confirmation",
   "FileDialogAllTypes": "All types",
@@ -585,7 +585,7 @@
   "UserProfilesSetProfileImage": "Set Profile Image",
   "UserProfileEmptyNameError": "Name is required",
   "UserProfileNoImageError": "Profile image must be set",
-  "GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
+  "GameUpdateWindowHeading": "Manage Updates for {0} ({1})",
   "SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
   "SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
   "UserProfilesName": "Name:",
diff --git a/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs b/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs
index c3ba623017..c57b3a26a7 100644
--- a/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs
+++ b/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs
@@ -3,23 +3,17 @@ using Ryujinx.Ava.Common.Locale;
 
 namespace Ryujinx.Ava.UI.Models
 {
-    internal class TitleUpdateModel
+    public class TitleUpdateModel
     {
-        public bool IsEnabled { get; set; }
-        public bool IsNoUpdate { get; }
         public ApplicationControlProperty Control { get; }
         public string Path { get; }
 
-        public string Label => IsNoUpdate
-            ? LocaleManager.Instance[LocaleKeys.NoUpdate]
-            : string.Format(LocaleManager.Instance[LocaleKeys.TitleUpdateVersionLabel], Control.DisplayVersionString.ToString(),
-                Path);
+        public string Label => string.Format(LocaleManager.Instance[LocaleKeys.TitleUpdateVersionLabel], Control.DisplayVersionString.ToString());
 
-        public TitleUpdateModel(ApplicationControlProperty control, string path, bool isNoUpdate = false)
+        public TitleUpdateModel(ApplicationControlProperty control, string path)
         {
             Control = control;
             Path = path;
-            IsNoUpdate = isNoUpdate;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
index f86cda21a2..2954021553 100644
--- a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
@@ -1601,13 +1601,9 @@ namespace Ryujinx.Ava.UI.ViewModels
 
         public async void OpenTitleUpdateManager()
         {
-            ApplicationData selection = SelectedApplication;
-            if (selection != null)
+            if (SelectedApplication != null)
             {
-                if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
-                {
-                    await new TitleUpdateWindow(VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(desktop.MainWindow);
-                }
+                await TitleUpdateWindow.Show(VirtualFileSystem, ulong.Parse(SelectedApplication.TitleId, NumberStyles.HexNumber), SelectedApplication.TitleName);
             }
         }
 
diff --git a/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs
new file mode 100644
index 0000000000..131ebd25b8
--- /dev/null
+++ b/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs
@@ -0,0 +1,226 @@
+using Avalonia.Collections;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Threading;
+using LibHac.Common;
+using LibHac.Fs;
+using LibHac.Fs.Fsa;
+using LibHac.FsSystem;
+using LibHac.Ns;
+using LibHac.Tools.FsSystem;
+using LibHac.Tools.FsSystem.NcaUtils;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.Models;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Utilities;
+using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.HOS;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using SpanHelpers = LibHac.Common.SpanHelpers;
+using Path = System.IO.Path;
+
+namespace Ryujinx.Ava.UI.ViewModels;
+
+public class TitleUpdateViewModel : BaseModel
+{
+    public TitleUpdateMetadata _titleUpdateWindowData;
+    public readonly string     _titleUpdateJsonPath;
+    private VirtualFileSystem  _virtualFileSystem { get; }
+    private ulong              _titleId           { get; }
+    private string             _titleName         { get; }
+
+    private AvaloniaList<TitleUpdateModel> _titleUpdates = new();
+    private AvaloniaList<object> _views = new();
+    private object _selectedUpdate;
+
+    public AvaloniaList<TitleUpdateModel> TitleUpdates
+    {
+        get => _titleUpdates;
+        set
+        {
+            _titleUpdates = value;
+            OnPropertyChanged();
+        }
+    }
+
+    public AvaloniaList<object> Views
+    {
+        get => _views;
+        set
+        {
+            _views = value;
+            OnPropertyChanged();
+        }
+    }
+
+    public object SelectedUpdate
+    {
+        get => _selectedUpdate;
+        set
+        {
+            _selectedUpdate = value;
+            OnPropertyChanged();
+        }
+    }
+
+    public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
+    {
+        _virtualFileSystem = virtualFileSystem;
+
+        _titleId   = titleId;
+        _titleName = titleName;
+
+        _titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
+
+        try
+        {
+            _titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_titleUpdateJsonPath);
+        }
+        catch
+        {
+            Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {_titleId} at {_titleUpdateJsonPath}");
+
+            _titleUpdateWindowData = new TitleUpdateMetadata
+            {
+                Selected = "",
+                Paths    = new List<string>()
+            };
+        }
+
+        LoadUpdates();
+    }
+
+    private void LoadUpdates()
+    {
+        foreach (string path in _titleUpdateWindowData.Paths)
+        {
+            AddUpdate(path);
+        }
+
+        TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null);
+
+        SelectedUpdate = selected;
+
+        SortUpdates();
+    }
+
+    public void SortUpdates()
+    {
+        var list = TitleUpdates.ToList();
+
+        list.Sort((first, second) =>
+        {
+            if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
+            {
+                return -1;
+            }
+            else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
+            {
+                return 1;
+            }
+
+            return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
+        });
+
+        Views.Clear();
+        Views.Add(new BaseModel());
+        Views.AddRange(list);
+
+        if (SelectedUpdate == null)
+        {
+            SelectedUpdate = Views[0];
+        }
+        else if (!TitleUpdates.Contains(SelectedUpdate))
+        {
+            if (Views.Count > 1)
+            {
+                SelectedUpdate = Views[1];
+            }
+            else
+            {
+                SelectedUpdate = Views[0];
+            }
+        }
+    }
+
+    private void AddUpdate(string path)
+    {
+        if (File.Exists(path) && TitleUpdates.All(x => x.Path != path))
+        {
+            using FileStream file = new(path, FileMode.Open, FileAccess.Read);
+
+            try
+            {
+                (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
+
+                if (controlNca != null && patchNca != null)
+                {
+                    ApplicationControlProperty controlData = new();
+
+                    using UniqueRef<IFile> nacpFile = new();
+
+                    controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
+                    nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
+
+                    TitleUpdates.Add(new TitleUpdateModel(controlData, path));
+                }
+                else
+                {
+                    Dispatcher.UIThread.Post(async () =>
+                    {
+                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
+                    });
+                }
+            }
+            catch (Exception ex)
+            {
+                Dispatcher.UIThread.Post(async () =>
+                {
+                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, path));
+                });
+            }
+        }
+    }
+
+    public void RemoveUpdate(TitleUpdateModel update)
+    {
+        TitleUpdates.Remove(update);
+
+        SortUpdates();
+    }
+
+    public async void Add()
+    {
+        OpenFileDialog dialog = new()
+        {
+            Title         = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
+            AllowMultiple = true
+        };
+
+        dialog.Filters.Add(new FileDialogFilter
+        {
+            Name       = "NSP",
+            Extensions = { "nsp" }
+        });
+
+        if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+        {
+            string[] files = await dialog.ShowAsync(desktop.MainWindow);
+
+            if (files != null)
+            {
+                foreach (string file in files)
+                {
+                    AddUpdate(file);
+                }
+            }
+        }
+
+        SortUpdates();
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml b/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml
index b4f2e1014e..ec931dd965 100644
--- a/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml
+++ b/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml
@@ -107,6 +107,7 @@
             VerticalAlignment="Stretch">
             <ListBox
                 Name="SaveList"
+                VirtualizationMode="None"
                 Items="{Binding Views}"
                 HorizontalAlignment="Stretch"
                 VerticalAlignment="Stretch">
@@ -116,6 +117,9 @@
                         <Setter Property="Margin" Value="5" />
                         <Setter Property="CornerRadius" Value="4" />
                     </Style>
+                    <Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
+                        <Setter Property="IsVisible" Value="False" />
+                    </Style>
                 </ListBox.Styles>
                 <ListBox.ItemTemplate>
                     <DataTemplate x:DataType="models:SaveModel">
diff --git a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml
index 5a69be9b09..e985803863 100644
--- a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml
+++ b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml
@@ -1,115 +1,135 @@
-<window:StyleableWindow
+<UserControl
     x:Class="Ryujinx.Ava.UI.Windows.TitleUpdateWindow"
     xmlns="https://github.com/avaloniaui"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
-    Width="600"
-    Height="400"
-    MinWidth="600"
-    MinHeight="400"
-    MaxWidth="600"
-    MaxHeight="400"
-    SizeToContent="Height"
-    WindowStartupLocation="CenterOwner"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    Width="500"
+    Height="300"
     mc:Ignorable="d"
+    x:CompileBindings="True"
+    x:DataType="viewModels:TitleUpdateViewModel"
     Focusable="True">
-    <Grid Margin="15">
+    <Grid>
         <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="Auto" />
             <RowDefinition Height="*" />
             <RowDefinition Height="Auto" />
         </Grid.RowDefinitions>
-        <TextBlock
-            Name="Heading"
-            Grid.Row="1"
-            MaxWidth="500"
-            Margin="20,15,20,20"
-            HorizontalAlignment="Center"
-            VerticalAlignment="Center"
-            LineHeight="18"
-            TextAlignment="Center"
-            TextWrapping="Wrap" />
         <Border
-            Grid.Row="2"
-            Margin="5"
+            Grid.Row="0"
+            Margin="0 0 0 24"
             HorizontalAlignment="Stretch"
             VerticalAlignment="Stretch"
-            BorderBrush="Gray"
-            BorderThickness="1">
-            <ScrollViewer
-                VerticalAlignment="Stretch"
-                HorizontalScrollBarVisibility="Auto"
-                VerticalScrollBarVisibility="Auto">
-                <ItemsControl
-                    Margin="10"
-                    HorizontalAlignment="Stretch"
-                    VerticalAlignment="Stretch"
-                    Items="{Binding _titleUpdates}">
-                    <ItemsControl.ItemTemplate>
-                        <DataTemplate>
-                            <RadioButton
-                                Padding="8,0"
-                                VerticalContentAlignment="Center"
-                                GroupName="Update"
-                                IsChecked="{Binding IsEnabled, Mode=TwoWay}">
-                                <Label
-                                    Margin="0"
+            BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
+            BorderThickness="1"
+            CornerRadius="5"
+            Padding="2.5">
+            <ListBox
+                VirtualizationMode="None"
+                Background="Transparent"
+                SelectedItem="{Binding SelectedUpdate, Mode=TwoWay}"
+                Items="{Binding Views}">
+                <ListBox.DataTemplates>
+                    <DataTemplate
+                        DataType="models:TitleUpdateModel">
+                        <Panel Margin="10">
+                            <TextBlock
+                                HorizontalAlignment="Left"
+                                VerticalAlignment="Center"
+                                TextWrapping="Wrap"
+                                Text="{Binding Label}" />
+                            <StackPanel
+                                Spacing="10"
+                                Orientation="Horizontal"
+                                HorizontalAlignment="Right">
+                                <Button
                                     VerticalAlignment="Center"
-                                    Content="{Binding Label}"
-                                    FontSize="12" />
-                            </RadioButton>
-                        </DataTemplate>
-                    </ItemsControl.ItemTemplate>
-                </ItemsControl>
-            </ScrollViewer>
+                                    HorizontalAlignment="Right"
+                                    Padding="10"
+                                    MinWidth="0"
+                                    MinHeight="0"
+                                    Click="OpenLocation">
+                                    <ui:SymbolIcon
+                                        Symbol="OpenFolder"
+                                        HorizontalAlignment="Center"
+                                        VerticalAlignment="Center" />
+                                </Button>
+                                <Button
+                                    VerticalAlignment="Center"
+                                    HorizontalAlignment="Right"
+                                    Padding="10"
+                                    MinWidth="0"
+                                    MinHeight="0"
+                                    Click="RemoveUpdate">
+                                    <ui:SymbolIcon
+                                        Symbol="Cancel"
+                                        HorizontalAlignment="Center"
+                                        VerticalAlignment="Center" />
+                                </Button>
+                            </StackPanel>
+                        </Panel>
+                    </DataTemplate>
+                    <DataTemplate
+                        DataType="viewModels:BaseModel">
+                        <Panel
+                            Height="33"
+                            Margin="10">
+                            <TextBlock
+                                HorizontalAlignment="Left"
+                                VerticalAlignment="Center"
+                                TextWrapping="Wrap"
+                                Text="{locale:Locale NoUpdate}" />
+                        </Panel>
+                    </DataTemplate>
+                </ListBox.DataTemplates>
+                <ListBox.Styles>
+                    <Style Selector="ListBoxItem">
+                        <Setter Property="Background" Value="Transparent" />
+                    </Style>
+                </ListBox.Styles>
+            </ListBox>
         </Border>
-        <DockPanel
-            Grid.Row="3"
-            Margin="0"
+        <Panel
+            Grid.Row="1"
             HorizontalAlignment="Stretch">
-            <DockPanel Margin="0" HorizontalAlignment="Left">
+            <StackPanel
+                Orientation="Horizontal"
+                Spacing="10"
+                HorizontalAlignment="Left">
                 <Button
                     Name="AddButton"
                     MinWidth="90"
-                    Margin="5"
-                    Command="{Binding Add}">
+                    Command="{ReflectionBinding Add}">
                     <TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
                 </Button>
-                <Button
-                    Name="RemoveButton"
-                    MinWidth="90"
-                    Margin="5"
-                    Command="{Binding RemoveSelected}">
-                    <TextBlock Text="{locale:Locale SettingsTabGeneralRemove}" />
-                </Button>
                 <Button
                     Name="RemoveAllButton"
                     MinWidth="90"
-                    Margin="5"
-                    Command="{Binding RemoveAll}">
+                    Click="RemoveAll">
                     <TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" />
                 </Button>
-            </DockPanel>
-            <DockPanel Margin="0" HorizontalAlignment="Right">
+            </StackPanel>
+            <StackPanel
+                Orientation="Horizontal"
+                Spacing="10"
+                HorizontalAlignment="Right">
                 <Button
                     Name="SaveButton"
                     MinWidth="90"
-                    Margin="5"
-                    Command="{Binding Save}">
+                    Click="Save">
                     <TextBlock Text="{locale:Locale SettingsButtonSave}" />
                 </Button>
                 <Button
                     Name="CancelButton"
                     MinWidth="90"
-                    Margin="5"
-                    Command="{Binding Close}">
+                    Click="Close">
                     <TextBlock Text="{locale:Locale InputDialogCancel}" />
                 </Button>
-            </DockPanel>
-        </DockPanel>
+            </StackPanel>
+        </Panel>
     </Grid>
-</window:StyleableWindow>
\ No newline at end of file
+</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs
index 848c5587f1..9d8b9a7b9c 100644
--- a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs
@@ -1,271 +1,116 @@
-using Avalonia.Collections;
 using Avalonia.Controls;
-using Avalonia.Threading;
-using LibHac.Common;
-using LibHac.Fs;
-using LibHac.Fs.Fsa;
-using LibHac.FsSystem;
-using LibHac.Ns;
-using LibHac.Tools.FsSystem;
-using LibHac.Tools.FsSystem.NcaUtils;
+using Avalonia.Interactivity;
+using Avalonia.Styling;
+using FluentAvalonia.UI.Controls;
 using Ryujinx.Ava.Common.Locale;
-using Ryujinx.Ava.UI.Controls;
 using Ryujinx.Ava.UI.Helpers;
 using Ryujinx.Ava.UI.Models;
-using Ryujinx.Common.Configuration;
+using Ryujinx.Ava.UI.ViewModels;
 using Ryujinx.Common.Utilities;
 using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.HOS;
-using System;
-using System.Collections.Generic;
+using Ryujinx.Ui.Common.Helper;
 using System.IO;
-using System.Linq;
 using System.Text;
-using Path = System.IO.Path;
-using SpanHelpers = LibHac.Common.SpanHelpers;
+using System.Threading.Tasks;
+using Button = Avalonia.Controls.Button;
 
 namespace Ryujinx.Ava.UI.Windows
 {
-    public partial class TitleUpdateWindow : StyleableWindow
+    public partial class TitleUpdateWindow : UserControl
     {
-        private readonly string     _titleUpdateJsonPath;
-        private TitleUpdateMetadata _titleUpdateWindowData;
-
-        private VirtualFileSystem              _virtualFileSystem { get; }
-        private AvaloniaList<TitleUpdateModel> _titleUpdates      { get; set; }
-
-        private ulong  _titleId   { get; }
-        private string _titleName { get; }
+        public TitleUpdateViewModel ViewModel;
 
         public TitleUpdateWindow()
         {
             DataContext = this;
 
             InitializeComponent();
-            
-            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})";
         }
 
         public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
         {
-            _virtualFileSystem = virtualFileSystem;
-            _titleUpdates      = new AvaloniaList<TitleUpdateModel>();
-
-            _titleId   = titleId;
-            _titleName = titleName;
-
-            _titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
-
-            try
-            {
-                _titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_titleUpdateJsonPath);
-            }
-            catch
-            {
-                _titleUpdateWindowData = new TitleUpdateMetadata 
-                {
-                    Selected = "",
-                    Paths    = new List<string>()
-                };
-            }
-
-            DataContext = this;
+            DataContext = ViewModel = new TitleUpdateViewModel(virtualFileSystem, titleId, titleName);
 
             InitializeComponent();
-
-            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})";
-
-            LoadUpdates();
-            PrintHeading();
         }
 
-        private void PrintHeading()
+        public static async Task Show(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
         {
-            Heading.Text = string.Format(LocaleManager.Instance[LocaleKeys.GameUpdateWindowHeading], _titleUpdates.Count - 1, _titleName, _titleId.ToString("X16"));
-        }
-
-        private void LoadUpdates()
-        {
-            _titleUpdates.Add(new TitleUpdateModel(default, string.Empty, true));
-
-            foreach (string path in _titleUpdateWindowData.Paths)
+            ContentDialog contentDialog = new()
             {
-                AddUpdate(path);
-            }
-
-            if (_titleUpdateWindowData.Selected == "")
-            {
-                _titleUpdates[0].IsEnabled = true;
-            }
-            else
-            {
-                TitleUpdateModel       selected = _titleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
-                List<TitleUpdateModel> enabled  = _titleUpdates.Where(x => x.IsEnabled).ToList();
-
-                foreach (TitleUpdateModel update in enabled)
-                {
-                    update.IsEnabled = false;
-                }
-
-                if (selected != null)
-                {
-                    selected.IsEnabled = true;
-                }
-            }
-
-            SortUpdates();
-        }
-
-        private void AddUpdate(string path)
-        {
-            if (File.Exists(path) && !_titleUpdates.Any(x => x.Path == path))
-            {
-                using FileStream file = new(path, FileMode.Open, FileAccess.Read);
-
-                try
-                {
-                    (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
-
-                    if (controlNca != null && patchNca != null)
-                    {
-                        ApplicationControlProperty controlData = new();
-
-                        using UniqueRef<IFile> nacpFile = new();
-
-                        controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
-                        nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
-
-                        _titleUpdates.Add(new TitleUpdateModel(controlData, path));
-
-                        foreach (var update in _titleUpdates)
-                        {
-                            update.IsEnabled = false;
-                        }
-
-                        _titleUpdates.Last().IsEnabled = true;
-                    }
-                    else
-                    {
-                        Dispatcher.UIThread.Post(async () =>
-                        {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
-                        });
-                    }
-                }
-                catch (Exception ex)
-                {
-                    Dispatcher.UIThread.Post(async () =>
-                    {
-                        await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, path));
-                    });
-                }
-            }
-        }
-
-        private void RemoveUpdates(bool removeSelectedOnly = false)
-        {
-            if (removeSelectedOnly)
-            {
-                _titleUpdates.RemoveAll(_titleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
-            }
-            else
-            {
-                _titleUpdates.RemoveAll(_titleUpdates.Where(x => !x.IsNoUpdate).ToList());
-            }
-
-            _titleUpdates.FirstOrDefault(x => x.IsNoUpdate).IsEnabled = true;
-
-            SortUpdates();
-            PrintHeading();
-        }
-
-        public void RemoveSelected()
-        {
-            RemoveUpdates(true);
-        }
-
-        public void RemoveAll()
-        {
-            RemoveUpdates();
-        }
-
-        public async void Add()
-        {
-            OpenFileDialog dialog = new()
-            {
-                Title         = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
-                AllowMultiple = true
+                PrimaryButtonText   = "",
+                SecondaryButtonText = "",
+                CloseButtonText     = "",
+                Content             = new TitleUpdateWindow(virtualFileSystem, titleId, titleName),
+                Title               = string.Format(LocaleManager.Instance[LocaleKeys.GameUpdateWindowHeading], titleName, titleId.ToString("X16"))
             };
 
-            dialog.Filters.Add(new FileDialogFilter
-            {
-                Name       = "NSP", 
-                Extensions = { "nsp" }
-            });
+            Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
+            bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false));
 
-            string[] files = await dialog.ShowAsync(this);
+            contentDialog.Styles.Add(bottomBorder);
 
-            if (files != null)
-            {
-                foreach (string file in files)
-                {
-                    AddUpdate(file);
-                }
-            }
-
-            SortUpdates();
-            PrintHeading();
+            await ContentDialogHelper.ShowAsync(contentDialog);
         }
 
-        private void SortUpdates()
+        private void Close(object sender, RoutedEventArgs e)
         {
-            var list = _titleUpdates.ToList();
-
-            list.Sort((first, second) =>
-            {
-                if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
-                {
-                    return -1;
-                }
-                else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
-                {
-                    return 1;
-                }
-
-                return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
-            });
-
-            _titleUpdates.Clear();
-            _titleUpdates.AddRange(list);
+            ((ContentDialog)Parent).Hide();
         }
 
-        public void Save()
+        public void Save(object sender, RoutedEventArgs e)
         {
-            _titleUpdateWindowData.Paths.Clear();
+            ViewModel._titleUpdateWindowData.Paths.Clear();
 
-            _titleUpdateWindowData.Selected = "";
+            ViewModel._titleUpdateWindowData.Selected = "";
 
-            foreach (TitleUpdateModel update in _titleUpdates)
+            foreach (TitleUpdateModel update in ViewModel.TitleUpdates)
             {
-                _titleUpdateWindowData.Paths.Add(update.Path);
+                ViewModel._titleUpdateWindowData.Paths.Add(update.Path);
 
-                if (update.IsEnabled)
+                if (update == ViewModel.SelectedUpdate)
                 {
-                    _titleUpdateWindowData.Selected = update.Path;
+                    ViewModel._titleUpdateWindowData.Selected = update.Path;
                 }
             }
 
-            using (FileStream titleUpdateJsonStream = File.Create(_titleUpdateJsonPath, 4096, FileOptions.WriteThrough))
+            using (FileStream titleUpdateJsonStream = File.Create(ViewModel._titleUpdateJsonPath, 4096, FileOptions.WriteThrough))
             {
-                titleUpdateJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true)));
+                titleUpdateJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(ViewModel._titleUpdateWindowData, true)));
             }
 
-            if (Owner is MainWindow window)
+            if (VisualRoot is MainWindow window)
             {
                 window.ViewModel.LoadApplications();
             }
 
-            Close();
+            ((ContentDialog)Parent).Hide();
+        }
+
+        private void OpenLocation(object sender, RoutedEventArgs e)
+        {
+            if (sender is Button button)
+            {
+                if (button.DataContext is TitleUpdateModel model)
+                {
+                    OpenHelper.LocateFile(model.Path);
+                }
+            }
+        }
+
+        private void RemoveUpdate(object sender, RoutedEventArgs e)
+        {
+            if (sender is Button button)
+            {
+                ViewModel.RemoveUpdate((TitleUpdateModel)button.DataContext);
+            }
+        }
+
+        private void RemoveAll(object sender, RoutedEventArgs e)
+        {
+            ViewModel.TitleUpdates.Clear();
+
+            ViewModel.SortUpdates();
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ui.Common/Helper/OpenHelper.cs b/Ryujinx.Ui.Common/Helper/OpenHelper.cs
index eaaa739246..3553489215 100644
--- a/Ryujinx.Ui.Common/Helper/OpenHelper.cs
+++ b/Ryujinx.Ui.Common/Helper/OpenHelper.cs
@@ -1,19 +1,75 @@
 using Ryujinx.Common.Logging;
 using System;
 using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
 
 namespace Ryujinx.Ui.Common.Helper
 {
-    public static class OpenHelper
+    public static partial class OpenHelper
     {
+        [LibraryImport("shell32.dll", SetLastError = true)]
+        public static partial int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, IntPtr apidl, uint dwFlags);
+
+        [LibraryImport("shell32.dll", SetLastError = true)]
+        public static partial void ILFree(IntPtr pidlList);
+
+        [LibraryImport("shell32.dll", SetLastError = true)]
+        public static partial IntPtr ILCreateFromPathW([MarshalAs(UnmanagedType.LPWStr)] string pszPath);
+
         public static void OpenFolder(string path)
         {
-            Process.Start(new ProcessStartInfo
+            if (Directory.Exists(path))
             {
-                FileName        = path,
-                UseShellExecute = true,
-                Verb            = "open"
-            });
+                Process.Start(new ProcessStartInfo
+                {
+                    FileName        = path,
+                    UseShellExecute = true,
+                    Verb            = "open"
+                });
+            }
+            else
+            {
+                Logger.Notice.Print(LogClass.Application, $"Directory \"{path}\" doesn't exist!");
+            }
+        }
+
+        public static void LocateFile(string path)
+        {
+            if (File.Exists(path))
+            {
+                if (OperatingSystem.IsWindows())
+                {
+                    IntPtr pidlList = ILCreateFromPathW(path);
+                    if (pidlList != IntPtr.Zero)
+                    {
+                        try
+                        {
+                            Marshal.ThrowExceptionForHR(SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0));
+                        }
+                        finally
+                        {
+                            ILFree(pidlList);
+                        }
+                    }
+                }
+                else if (OperatingSystem.IsMacOS())
+                {
+                    Process.Start("open", $"-R \"{path}\"");
+                }
+                else if (OperatingSystem.IsLinux())
+                {
+                    Process.Start("dbus-send", $"--session --print-reply --dest=org.freedesktop.FileManager1 --type=method_call /org/freedesktop/FileManager1 org.freedesktop.FileManager1.ShowItems array:string:\"file://{path}\" string:\"\"");
+                }
+                else
+                {
+                    OpenFolder(Path.GetDirectoryName(path));
+                }
+            }
+            else
+            {
+                Logger.Notice.Print(LogClass.Application, $"File \"{path}\" doesn't exist!");
+            }
         }
 
         public static void OpenUrl(string url)