Skip to content

Conversation

@agracio
Copy link

@agracio agracio commented Nov 5, 2025

Currently events and tasks have a lot of repetitive code, this RP attempts to remove some of the repetition starting with events.

Changes summary

  • Added new helper class ApiEventManager to wrap events code.
  • Refactored events in App.cs, BrowserWindow.cs, Tray.cs, AutoUpdater.cs, NativeTheme.cs, PowerMonitor.cs, Screen.cs, WebContents.cs
  • Changed event names in Tray and Screen API.

Different event naming and Tray API changes

Currently Electron.NET API has multiple event naming schemes making it harder to implement a single method for wrapping events, examples below. Event names in .NET API correspond to event names in TypeScript/JS implementation.

  • BrowserWindow API does not add any additional names to events.
BridgeConnector.Socket.On(eventName + id, () => { callback(); });
BridgeConnector.Socket.Emit("register-" + eventName, id);
  • App API adds -event to Emit() method.
BridgeConnector.Socket.On(eventName + id, () => { callback(); });
BridgeConnector.Socket.Emit("register-" + eventName + "-event", id);
  • Tray and Screen API was adding -event to On() method.
BridgeConnector.Socket.On(eventName + id + "-event", () => { callback(); });
BridgeConnector.Socket.Emit("register-" + eventName, id);

In order to keep different method signatures to a minimum I have renamed Tray and Screen API events in line with BrowserWindow.

This is a work in progress but would like to get some feedback to make sure the change is acceptable.

@FlorianRappl
Copy link
Collaborator

Actually much appreciated - with more time this is something on my list (really cumbersome code in some areas, could benefit a lot from some refactoring... - so great job 🚀 !).

Copy link
Collaborator

@FlorianRappl FlorianRappl left a comment

Choose a reason for hiding this comment

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

Yes, definitely appreciated and goes in the right direction. Just let me know when you are done / want to see it merged in.

@agracio
Copy link
Author

agracio commented Nov 5, 2025

Almost done with events but would also want to clean up at least some of the tasks code. I will let you know when events are done.

@agracio
Copy link
Author

agracio commented Nov 5, 2025

Events are done. Even managed to find an error in one of them.

Task optimisation is next but you can merge event changes first if you want.

@agracio
Copy link
Author

agracio commented Nov 5, 2025

Tasks will take significantly longer. There are many different types and of course different naming.

On subject of naming - is SocketIO case sensitive, there are some tasks that end in -completed some in -Completed and some in Completed, fingers crossed there aren't more.

@FlorianRappl
Copy link
Collaborator

Yeah so in general these strings are all case sensitive - personally, I'd make it consistent (I've seen that across the codebase many things in that area a bit inconsistent to write the least... - so using the opportunity to make the naming / transported names consistent would be appreciated).

Many thanks for your efforts - so we'll merge this one right now and do another PR at some point in time later? @agracio

@agracio
Copy link
Author

agracio commented Nov 5, 2025

Yes I would suggest to merge these changes first while I work on tasks. There is more than I initially thought.

@agracio
Copy link
Author

agracio commented Nov 5, 2025

Alternatively I can refactor App API to normalize it's event naming, this would not take long at all.

@FlorianRappl
Copy link
Collaborator

Alternatively I can refactor App API to normalize it's event naming, this would not take long at all.

OK let's add this then merge! Thanks!

@agracio
Copy link
Author

agracio commented Nov 5, 2025

All done. Please give it a thorough review.

Copy link
Collaborator

@FlorianRappl FlorianRappl left a comment

Choose a reason for hiding this comment

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

LGTM - at least I could not see anything going wrong here in the review pane. Let's merge and test with the preview version.

@FlorianRappl FlorianRappl merged commit 4671b9b into ElectronNET:develop Nov 6, 2025
2 of 3 checks passed
@agracio
Copy link
Author

agracio commented Nov 6, 2025

I have an off-topic question, currently supported Electron versions are 37 - 39. While it is possible to change version during development should a default version be one of the supported ones?

@FlorianRappl
Copy link
Collaborator

I have an off-topic question, currently supported Electron versions are 37 - 39. While it is possible to change version during development should a default version be one of the supported ones?

It's a good question - I'd say yes (preferably the most recent LTS; but I don't think the follow that model (all their releases have the same supported time range). So let's try to go for the most recent one then (39, even though 40 is on the horizon)?

@agracio
Copy link
Author

agracio commented Nov 6, 2025

Electron supports 3 latest releases, unfortunately they do not have a real LTS cycle like lets say Node.js. Each release is supported for around 6 months depending on Chromium release cycle. Current version is 39 which was released on 28th of October.

Current releases, version 36 is now EOL with version 40 stated for release on 13th of Jan next year.

Version Release Date EOL
39 2025-Oct-28 2026-May-05
38 2025-Sep-02 2026-Mar-10
37 2025-Jun-24 2026-Jan-13
36 2025-Apr-29 2025-Oct-28

Note how EOL date lines up with +3 release version so 36 EOL date equals 39 release date.

They are very strict in their support policy, any issues raised for EOL versions of Electron get an immediate reply along the lines of "this version of Electron is no longer supported try to reproduce the issue using supported version".

Electron releases: https://releases.electronjs.org/

@softworkz
Copy link
Contributor

One note about version selection: The selection dropdown is just a convenience feature, you can also specify different (=newer) versions in the .csproj file and it will work fine (just shown empty then in the project designer).

Only requirement: It must be specified as a 3-part version number. Specifying just two parts (like 37.1) will make electron-builder choke (unable to download), that's where the dropdown comes-in handy, allowing you to see only the available versions.

Getting the selection list dynamically updated at the user side is not possible without delivering a full project system (that would need to be delivered as a Visual Studio Extension MSIX), so the next best possible way is the Python script that is next to the XAML definition. It can be run manually or we could also have it been executed by Ninja as part of the nuget package build process.

@agracio
Copy link
Author

agracio commented Nov 6, 2025

I believe you are referring to a feature that is only available in Visual Studio, there are no version dropdowns in other IDEs and not sure where they are configured. Could you point to a place in the code where the versions are listed?

All I can find in solution files is version 30.4.0 specified in multiple location but no list. I am probably looking in the wrong location.

My suggestion was to move from version 30.4.0 to a supported version of Electron, 39 would be ideal since it is the latest version and will have support until May next year. Later versions can be incremented.

@softworkz
Copy link
Contributor

softworkz commented Nov 6, 2025

In Visual Studio, all the Electron.NET MSBuild properties can be set nicely in the project designer:

image

.

This UI is defined in the ElectronNETRules.Project.xaml file, which also contains the preselections:

image

.

The defaults are defined in the ElectronNET.props file.

Summary of where the files are effective

  • Visual Studio Only
    • ElectronNETRules.Project.xaml
    • ElectronNETRules.Project2.xaml
    • ElectronNET.DesignTime.targets
  • Visual Studio + MSBuild (all other IDEs)
    • ElectronNET.Core.props
    • ElectronNET.Core.targets
    • ElectronNET.LateImport.targets
    • ElectronNET.props
    • ElectronNET.targets

@agracio
Copy link
Author

agracio commented Nov 6, 2025

I see, unfortunately other IDEs do not pick up those options.

image

Options for setting Electron version are documented however my suggestion was to have the default to be Electron 37-39, preferably 39.

Not entirely sure if there is a point to have every single Electron revision listed in .xaml file would it not make more sense to have the latest revision of a specific major version only?
Especially for unsupported Electron versions that do not have changing versions, the latest released version is not going to change for example 32.3.3. 33.4.11, 34.5.8, 35.7.5 and so on.

@softworkz
Copy link
Contributor

Generally, if you ever want to work on any of the MSBuild stuff, I think it is mandatory to do this from within Visual Studio. It is easy to break things and also difficult to understand how this stuff is working. You also need to have and use the BinLog viewer. Finally, the "Project System Tools 2022" Visual Studio Extension is useful to get logs from design-time builds.

By hitting the "Show all files" button in the Solution Explorer, you get to see the "Imports" node, which allows you to inspect the whole tree of .props and .targets that are used, and in which order they are imported:

image

.

This tree is not VS specific - it's MSBuild logic and the same for all IDEs (but only VS shows it to you like this).

@softworkz
Copy link
Contributor

Options for setting Electron version are documented however my suggestion was to have the default to be Electron 37-39, preferably 39.

I do not mind changing the default.

Not entirely sure if there is a point to have every single Electron revision listed in .xaml file would it not make more sense to have the latest revision of a specific major version only?

Generally, the point is that each version has been the latest one at some point in time, and there can be good reasons for why you don't want to change that, that's my point of listing all versions and never remove any, because then it would no longer be shown in the app designer page. It's just a cosmetic thing, not a functional one and for the first-time release, we could surely drop all the older ones.

@agracio
Copy link
Author

agracio commented Nov 6, 2025

I think it is important to include all developers that use different tools and especially different OSes for dev. Visual Studio is only available on Windows.

  • VSCode - multiplatform IDE however it is not specific to .NET and tries to cater to all languages including dotnet, it's doing a decent job but is far from being an actual replacement for dotnet IDE.
  • Jetbrains Rider - another multiplatform .NET specific IDE. I have switched to it many years ago since it is considerably less bloated and offers features of full IDE including Resharper built in as part of IDE itself rather than an add-on.

To be fair version selector is not something that is absolutely essential and documentation makes it rather clear how to change version.

It's just a cosmetic thing, not a functional one and for the first-time release, we could surely drop all the older ones.

I would not say that it is hugely important the only up side is a much cleaner version dropdown showing only latest major versions. I do not mean that all old versions should be removed but having just the latest for the older version would make it more readable.
Then again it is such a tiny nit-pick considering that I do not even have access to that dropdown.

On a much lighter note I wish the dropdown was an actual issue - working on refactoring tasks and it's giving me a major headache with naming conventions seemingly changing between each file 🥲

@softworkz
Copy link
Contributor

I think it is important to include all developers that use different tools and especially different OSes for dev. Visual Studio is only available on Windows.

I'd say that primarily important for consumers of Electron.NET, not that much for working on the project itself, but anyway, you'll probably not be doing major MSBuild code changes and for everything else it's fine not to have VS.,

@agracio
Copy link
Author

agracio commented Nov 6, 2025

@softworkz I believe you mentioned something about optimising Electron app lifetime.
Currently if there is .NET exception in AspNet app the front end disconnects without any visual queues visible to end user other than becoming unresponsive to commands. Closing such hanging Electron app leaves 3 orphan electron.exe processes.
It is very easy to reproduce using demo app.

I know that you have written about it but not sure which of the very long threads to look at. Is this something you also added to your commit?

@softworkz
Copy link
Contributor

@agracio - See this PR: #908

It is one part of the things I've done to achieve proper shutdown.

Copy link
Contributor

@softworkz softworkz left a comment

Choose a reason for hiding this comment

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

This PR wasn't ready for merge, but no big deal, it can be fixed.


internal static class ApiEventManager
{
internal static void AddEvent(string eventName, object id, Action callback, Action value, string suffix = "")
Copy link
Contributor

Choose a reason for hiding this comment

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

Object ids should be int, not object. int is what GetHashCode() returns

{
if (callback == null)
{
BridgeConnector.Socket.On(eventName + id, () => { callback(); });
Copy link
Contributor

Choose a reason for hiding this comment

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

You need int.ToString(CultureInfo.InvariantCulture), otherwise, for some languages, integers will have punctuations (throusand separators) with the default .ToString() - which is called for + concatenations.

{
if (callback == null)
{
BridgeConnector.Socket.On(eventName + id, () => { callback(); });
Copy link
Contributor

Choose a reason for hiding this comment

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

callback invocation needs null-check - like callback?.Invoke()


internal static class ApiEventManager
{
internal static void AddEvent(string eventName, object id, Action callback, Action value, string suffix = "")
Copy link
Contributor

Choose a reason for hiding this comment

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

The major problem here is that callback will always be null when entering this function, because callback += value; will not modify the delegate of the caller, only the local one.
This means effectively, that once a second event registration is made, the first one will stop working.

BridgeConnector.Socket.Emit($"register-{eventName}{suffix}", id);
}
callback += value;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally, the pattern here is not suitable, you should rather build a dictionary of event delegates - ideally a ConcurrentDiictionary like I did for the properties, because that will also help with concurrency (the current pattern is not thread-safe).

Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about it, a ConcurrentDiictionary doesn't help here, because it doesn't allow you to synchronize removals (to make sure you unregister socket events without that a new registration happens in parallel).
You'll need a regular Dictionary with loccking instead.

@FlorianRappl FlorianRappl added this to the 0.1.0 milestone Nov 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants