Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 7 additions & 79 deletions src/DynamoCoreWpf/Controls/StartPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
using Dynamo.Configuration;
using Dynamo.Logging;
using Dynamo.Utilities;
using Dynamo.ViewModels;
using Dynamo.Wpf.Properties;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Expand All @@ -16,7 +10,12 @@
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using static Dynamo.Wpf.Interfaces.ResourceNames;
using Dynamo.Configuration;
using Dynamo.Logging;
using Dynamo.Utilities;
using Dynamo.ViewModels;
using Dynamo.Wpf.Properties;
using Newtonsoft.Json;
using NotificationObject = Dynamo.Core.NotificationObject;

namespace Dynamo.UI.Controls
Expand Down Expand Up @@ -120,7 +119,6 @@ public class StartPageViewModel : ViewModelBase
ObservableCollection<SampleFileEntry> sampleFiles = null;
ObservableCollection<StartPageListItem> recentFiles = null;
ObservableCollection<StartPageListItem> backupFiles = null;
readonly ObservableCollection<StartPageListItem> templateFiles;
internal readonly DynamoViewModel DynamoViewModel;
private readonly bool isFirstRun;

Expand All @@ -132,7 +130,6 @@ internal StartPageViewModel(DynamoViewModel dynamoViewModel, bool isFirstRun)
this.recentFiles = new ObservableCollection<StartPageListItem>();
this.sampleFiles = new ObservableCollection<SampleFileEntry>();
this.backupFiles = new ObservableCollection<StartPageListItem>();
this.templateFiles = new ObservableCollection<StartPageListItem>();


#region File Operations
Expand Down Expand Up @@ -216,67 +213,7 @@ internal StartPageViewModel(DynamoViewModel dynamoViewModel, bool isFirstRun)
var dvm = this.DynamoViewModel;
RefreshRecentFileList(dvm.RecentFiles, true);
RefreshBackupFileList(dvm.Model.PreferenceSettings.BackupFiles);
LoadTemplates();
dvm.RecentFiles.CollectionChanged += OnRecentFilesChanged;


}


private void LoadTemplates()
{
// Retrieve the current Temlates location from Dynamo properties
var templatesDirectory = DynamoViewModel.Model.PathManager.TemplatesDirectory;

if (Directory.Exists(templatesDirectory))
{
var rootDynPaths = new List<string>();
string[] filePaths = Directory.GetFiles(templatesDirectory, "*.dyn"); // This could change if we move to *dyt

// We only collect the files in the root
if (filePaths.Length != 0)
{
foreach (string path in filePaths)
{
rootDynPaths.Add(path);
}
}

// Make comment on legacy use of StartPage.xaml.cs
if (rootDynPaths.Any())
{
foreach (var filePath in rootDynPaths)
{
AddTemplateListItemFromPath(filePath);
}
}
}
}

private void AddTemplateListItemFromPath(string filePath)
{
var extension = Path.GetExtension(filePath).ToUpper();
// If not extension specified and code reach here, this means this is still a valid file
// only without file type. Otherwise, simply take extension substring skipping the 'dot'.
var subScript = extension.StartsWith('.') ? extension.Substring(1) : "";
var caption = Path.GetFileNameWithoutExtension(filePath);

// deserializes the file only once
var properties = GetFileProperties(filePath);

var templateItem = new StartPageListItem(caption)
{
ContextData = filePath,
ToolTip = filePath,
SubScript = subScript,
Description = properties.description,
Thumbnail = properties.thumbnail,
Author = properties.author,
DateModified = properties.date,
ClickAction = StartPageListItem.Action.FilePath,
};

this.TemplateFiles.Add(templateItem);
}

internal void WalkDirectoryTree(System.IO.DirectoryInfo root, SampleFileEntry rootProperty)
Expand Down Expand Up @@ -448,15 +385,6 @@ public ObservableCollection<SampleFileEntry> SampleFiles
get { return this.sampleFiles; }
}

/// <summary>
/// A collection of Dynamo Template files
/// Fetched at load time from the current Dynamo Templates Propoerties location
/// </summary>
public ObservableCollection<StartPageListItem> TemplateFiles
{
get { return this.templateFiles; }
}

public string BackupTitle
{
get
Expand Down Expand Up @@ -542,7 +470,7 @@ private void RefreshFileList(ObservableCollection<StartPageListItem> files,
var extension = Path.GetExtension(filePath).ToUpper();
// If not extension specified and code reach here, this means this is still a valid file
// only without file type. Otherwise, simply take extension substring skipping the 'dot'.
var subScript = extension.StartsWith('.') ? extension.Substring(1) : "";
var subScript = extension.StartsWith(".") ? extension.Substring(1) : "";
var caption = Path.GetFileNameWithoutExtension(filePath);

// deserializes the file only once
Expand Down
4 changes: 3 additions & 1 deletion src/DynamoCoreWpf/DynamoCoreWpf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

<Target Name="NpmRunBuildHomePage" BeforeTargets="BeforeBuild">
<PropertyGroup>
<PackageVersion>1.0.28</PackageVersion>
<PackageVersion>1.0.26</PackageVersion>
<PackageName>DynamoHome</PackageName>
</PropertyGroup>
<Exec Command="$(PowerShellCommand) -ExecutionPolicy Bypass -File &quot;$(SolutionDir)pkgexist.ps1&quot; &quot;$(PackageName)&quot; &quot;$(PackageVersion)&quot;" ConsoleToMSBuild="true">
Expand Down Expand Up @@ -799,7 +799,9 @@
<Compile Include="Views\GuidedTour\SurveyPopupWindow.xaml.cs">
<DependentUpon>SurveyPopupWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Views\HomePage\HomePage.xaml.cs" />
<Compile Include="Views\Input\ParameterEditor.cs" />
<Compile Include="Views\PackageManager\Components\PackageManagerWizard\PackageManagerWizard.xaml.cs" />
Comment on lines +802 to +804
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HomePage.xaml.cs and PackageManagerWizard.xaml.cs are now included twice in the project (also present later with <DependentUpon>). Duplicate <Compile Include=...> items typically cause MSBuild errors (duplicate items) and should be removed—keep only the existing entries that include DependentUpon.

Suggested change
<Compile Include="Views\HomePage\HomePage.xaml.cs" />
<Compile Include="Views\Input\ParameterEditor.cs" />
<Compile Include="Views\PackageManager\Components\PackageManagerWizard\PackageManagerWizard.xaml.cs" />
<Compile Include="Views\Input\ParameterEditor.cs" />

Copilot uses AI. Check for mistakes.
<Compile Include="Views\PackageManager\Controls\CustomBrowserControl.xaml.cs" />
<Compile Include="Views\PackageManager\Controls\FilterTagControl.xaml.cs" />
<Compile Include="Views\PackageManager\Controls\LoadingAnimationStripeControl.xaml.cs" />
Expand Down
1 change: 0 additions & 1 deletion src/DynamoCoreWpf/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Dynamo.PackageManager.ViewModels.PackageManagerSearchElementViewModel.IsInstalle
Dynamo.PackageManager.ViewModels.PackageManagerSearchElementViewModel.IsInstalledVersionSelected.get -> bool
Dynamo.PackageManager.ViewModels.PackageManagerSearchElementViewModel.IsPublishedByDynamoTeam.get -> bool
Dynamo.PackageManager.ViewModels.PackageManagerSearchElementViewModel.IsUninstallState.get -> bool
Dynamo.UI.Controls.StartPageViewModel.TemplateFiles.get -> System.Collections.ObjectModel.ObservableCollection<Dynamo.UI.Controls.StartPageListItem>
Dynamo.UI.Views.ScriptObject.ResetSettings() -> void
Dynamo.UI.Views.ScriptObject.ScriptObject(System.Action<bool> requestLaunchDynamo, System.Action<string> requestImportSettings, System.Func<bool> requestSignIn, System.Func<bool> requestSignOut, System.Action requestResetSettings) -> void
Dynamo.ViewModels.DynamoViewModel.OnlineAccess.get -> bool
Expand Down
46 changes: 8 additions & 38 deletions src/DynamoCoreWpf/Views/HomePage/HomePage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Autodesk.DesignScript.Runtime;
Expand Down Expand Up @@ -273,25 +272,24 @@ internal void LoadingDone()
if (startPage == null) { return; }

SendGuidesData();
_ = SendSamplesData();
_ = SendTemplateData();
_ = SendRecentGraphsData();
SendSamplesData();
SendRecentGraphsData();
SendVideoData();
SetLocale();
}

private void RecentFiles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
var recentFiles = startPage.RecentFiles?.DistinctBy(x => x.ContextData).ToList();
_ = LoadGraphs(recentFiles);
LoadGraphs(recentFiles);
}

#region FrontEnd Initialization Calls
/// <summary>
/// Sends graph data to react app
/// </summary>
/// <param name="data"></param>
private async Task LoadGraphs(List<StartPageListItem> data)
private async void LoadGraphs(List<StartPageListItem> data)
{
if (data == null) { return; }
string jsonData = JsonSerializer.Serialize(data);
Expand All @@ -302,26 +300,10 @@ private async Task LoadGraphs(List<StartPageListItem> data)
}
Comment on lines 292 to 300
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoadGraphs was changed from async Task to async void. Since this isn’t an event handler, async void exceptions propagate to the WPF synchronization context and can crash the process (e.g., if ExecuteScriptAsync faults). Prefer restoring a Task return type and either await it from an async caller or keep fire-and-forget with explicit exception handling/logging.

Copilot uses AI. Check for mistakes.
}


/// <summary>
/// Sends graph data to react app
/// </summary>
/// <param name="data"></param>
private async Task LoadTemplates(List<StartPageListItem> data)
{
if (data == null) { return; }
string jsonData = JsonSerializer.Serialize(data);

if (dynWebView?.CoreWebView2 != null)
{
await dynWebView.CoreWebView2.ExecuteScriptAsync(@$"window.receiveTemplatesDataFromDotNet({jsonData})");
}
}

/// <summary>
/// Sends samples data to react app
/// </summary>
private async Task SendSamplesData()
private async void SendSamplesData()
{
if (!this.startPage.SampleFiles.Any()) return;

Expand All @@ -333,21 +315,9 @@ private async Task SendSamplesData()
}
Comment on lines 306 to 315
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SendSamplesData was changed to async void but it’s not an event handler. Exceptions from ExecuteScriptAsync will be raised on the WPF sync context (potentially crashing the app) and can’t be observed/handled by the caller. Prefer restoring async Task and either await it from an async caller or keep fire-and-forget with explicit exception handling/logging.

Copilot uses AI. Check for mistakes.
}

/// <summary>
/// Sends samples data to react app
/// </summary>
private async Task SendTemplateData()
{
var items = startPage.TemplateFiles?.DistinctBy(x => x.ContextData).ToList();
if (items != null && items.Any())
{
await LoadTemplates(items);
}
}

private async Task SendRecentGraphsData()
private async void SendRecentGraphsData()
{
// Send user preferences (could be split to a separate call later instead of coupling with recent files).
// Send user preferences
if (dynWebView?.CoreWebView2 != null)
{
if (startPage.DynamoViewModel.PreferenceSettings.HomePageSettings != null)
Expand All @@ -364,7 +334,7 @@ private async Task SendRecentGraphsData()
var recentFiles = startPage.RecentFiles?.DistinctBy(x => x.ContextData).ToList();
if (recentFiles != null && recentFiles.Any())
{
await LoadGraphs(recentFiles);
LoadGraphs(recentFiles);
}

if (startPage.DynamoViewModel != null && startPage.DynamoViewModel.RecentFiles != null)
Expand Down
Loading