NeHive is a:
✔ Framework for writing UI directly using C# functions
✔ Fine-grained reactive system inspired by SolidJS / Vue3
✔ UI that automatically tracks Signal dependencies and updates precisely
✔ Solution that requires NO XAML / INotifyPropertyChanged
Core philosophy:
In traditional .NET UI development (WPF / Avalonia / WinUI), we are often forced to accept these "black box" overheads:
- Bloated MVVM Glue Code: Tedious layer separation, disconnection between state and view, and a massive amount of repetitive boilerplate code.
- Cumbersome INotifyPropertyChanged: Manually triggering notifications, or relying heavily on heavy source generators.
- Hard-to-Debug XAML Bindings: Runtime binding failures only output logs, making it impossible to trace issues with breakpoints.
- Uncontrollable UI Update Granularity: Relying on implicit framework refreshes, with no way to achieve precise and efficient partial rendering.
- Severe Concept Fragmentation: Independent concepts like Templates, Triggers, Converters, State Machines, Attached Properties, Commands, and Value Converters lead to an inconsistent mental model, keeping learning and maintenance costs high.
- Syntax Disconnection: Huge gaps between markup languages and backend syntax prevent the flexible use of native C# capabilities to build dynamic UIs.
- Verbose Style Syntax: Native style attributes are complex; code quickly becomes bloated and hard to reuse when combining multiple styles.
NeHive is not just another wheel; it is a brand-new philosophy for building UI. We firmly believe that:
UI = f(State)
- Unified Mental Model: The entire framework is built around three core primitives: Scope (lifecycle), Signal (reactive state), and Effect (side effect). All capabilities are composed of these three, keeping the concept minimal.
- State as a Signal: Declarative reactive states where changes are fully trackable and predictable.
- UI as a Pure Function: Views map directly to states with a clear and intuitive structure, written entirely in native C# syntax.
- Precise Targeted Updates: Automatic dependency collection ensures that state changes only update the corresponding atomic nodes.
- Explicit Lifecycle: Managed via a Scope Tree to prevent memory leaks right at the architectural level.
- Syntax and Paradigm Freedom: Features like templates, triggers, and data conversion are implemented using C# expressions + reactivity, eliminating the need to write and maintain dedicated converters. Declarative and imperative paradigms can be mixed freely without learning extra syntax.
- Atomic Styling System: Features a built-in Tailwind-style
strStyle. It uses concise utility classes to combine styles, saying goodbye to verbose native styling code while making writing highly efficient and reusable. - Extremely Low Learning Curve: Master the three core concepts, and you master all the functionalities of the framework.
The minimal UI component in NeHive looks like this:
public static IElement Counter()
{
var count = new MutSignal<int>(0);
return HStackPanel(new()
{
HTextBlock(
() => $"Count: {count.RxValue}",
strStyle: "text-xl"
),
HButton(
"Add",
onClick: _ => count.RxValue++
)
});
}This component demonstrates the fundamental reactive mechanism of NeHive:
countis a Signal (reactive state).HTextBlock(() => ...)automatically subscribes tocount.RxValue.- When
count.RxValuechanges: → Only the text node that depends on it will update. → The UI will NOT rebuild as a whole. - The click event of
HButtondirectly mutates the Signal state.
Final Effect: Click the button → Count updates in real-time.
NeHive's UI code features the following characteristics:
- Functions as UI: Components are essentially pure functions that return an
IElement. - Localized State: State is declared directly inside the component, removing the need for a ViewModel.
- Implicit Reactivity: No manual subscriptions or update notifications required.
- Declarative Structure: The UI structure maps directly to the code layout.
- Low Abstraction Layer: No intermediate layers like XAML / Binding / VM.
Simply put:
UI = f(State), where state changes automatically drive view updates.
NeHive unifies three core capabilities, forming a complete ecosystem from the low-level runtime to the top-level UI:
┌─────────────────────────────┐
│ NeHive.UI.Avalonia │ <-- Avalonia-based declarative functional UI framework
└──────────────┬──────────────┘
│ (Depends on)
┌──────────────▼──────────────┐
│ NeHive.Reactive │ <-- Fine-grained reactive runtime (Signal/Effect)
└──────────────┬──────────────┘
│ (Depends on)
┌──────────────▼──────────────┐
│ NeHive.Model │ <-- Runtime semantic model & lifecycle management (Scope)
└─────────────────────────────┘
- NeHive.Model: The runtime semantic model layer. It provides
Scope,Context, and lifecycle management. - NeHive.Reactive: The fine-grained reactive runtime core. It provides core reactive primitives like
Signal,Computed,Effect,AsyncMemo,ReactiveFlow, andListStore. - NeHive.UI.Avalonia: The top-level functional UI implementation based on Avalonia. It provides functional components, control flow components, an atomic styling system, and reactive drivers.
👉 The best way to understand NeHive is not by reading the documentation, but by running it yourself!
Important
The sample project requires .NET 8 SDK or later.
Currently supported:
- .NET 8
- .NET 9
- .NET 10
Please make sure an appropriate version is installed on your machine before running the sample.
git clone https://github.com/oanlit/NeHive.git
cd NeHive/samples/NeHive.Sample.Avalonia
dotnet run- 🧩 Functional Component UI: Completely detached from XAML, enjoying ultimate compile-time type safety and hot-reload potential.
- ⚡ Control Flow Components: Native support for reactive control flow UIs such as
Switch/ForEach/Match. - 🌳 Scope Tree Lifecycle: Experience the elegance of states and side effects (Effects) being automatically and safely released when their scope is destroyed.
In NeHive, component design completely returns to the declarative pure C# function paradigm of UI = f(State). Without writing verbose XAML and heavy base class inheritance chains, logic and views become highly cohesive.
To meet business scenarios of varying complexities, NeHive refines components into two core engineering paradigms:
Suitable for components that do not need to manage their own lifecycle or host underlying unmanaged resources.
- 💡 Data-Driven Mechanism: The component can receive ordinary static data (like the
SongInfostruct below) just like a regular C# function, rendering it as a local view snapshot for a single run. If dynamic reactive updates for parameters are needed, upstream callers can either explicitly pass aSignalobject or pass a Lambda closure to trigger topological tracking internally via.RxValue.
// Scopeless Component: Ready to use on the fly; data is driven entirely by external parameters, without intervening in lifecycle management.
private static IElement Audio(SongInfo? song)
{
return HStackPanel(new(strStyle: "w-110 gap-4 horizontal items-center")
{
Show(new(song?.CoverPath is not null)
{
IfFalse = () => HButton(strStyle: "w-32 h-32 bg-gray-200 rounded-xl"),
IfTrue = () => HUriImage(song?.CoverPath, stretch: Stretch.UniformToFill, strStyle: "...")
}),
HStackPanel(new(strStyle: "gap-1 vertical")
{
// Static passing, ideal for a single-rendering snapshot
HTextBlock(song?.Title ?? "Unknown Title", strStyle: "max-w-100 text-base font-semibold fg-gray-800"),
// To support reactive updates, you can pass a closure (assuming the parameter is changed to a closure or Signal)
// HTextBlock(() => currentSong.RxValue?.Title ?? "Unknown Title", ...)
HTextBlock(song?.Artist ?? "Unknown Artist", strStyle: "max-w-75 text-sm fg-gray-500"),
HTextBlock(song?.Album ?? "Unknown Album", strStyle: "max-w-50 text-xs fg-gray-500")
})
});
}When a component needs to manage its own lifecycle or take over the lifecycle of underlying native resources (such as initializing/disposing of an unmanaged engine or mounting asynchronous network requests), a UiScope is injected via Element.WithScope for unified hosting. The lifecycle topology within the component will be fully mounted to the scope tree, ensuring predictable behavior and resource safety.
// Scoped Component: Features an independent runtime context and explicit lifecycle control
public static IElement CorePlayer() => Element.WithScope(uiScope =>
{
// 1. Initialize local states and engines belonging to this component's lifecycle (using scope to manage resources)
var (libVlc, mediaPlayer) = uiScope.CreateMediaPlayer();
var playlist = new MutSignal<IReadOnlyList<TrackInfo>>([]);
var currentIndex = new MutSignal<int>(-1);
// 2. Declare local asynchronous derived streams and side effects (lifecycle automatically and safely releases upon uiScope destruction)
var songInfo = uiScope.CreateAsyncMemo(async epochScope => { /* ... */ });
uiScope.CreateEffect(epochScope => { /* ... */ });
// 3. Return the declarative UI topology structure
return rootElement;
});The following production-ready code snippets are taken from the Music Player sample project, demonstrating how NeHive provides rigorous and highly cohesive engineering solutions when facing complex, highly interactive desktop industrial scenarios:
By leveraging Scope runtime semantics, the disposal logic of underlying unmanaged resources (such as MediaPlayer) can perfectly co-exist within the UI component's lifecycle. When a UI component is unmounted due to routing switches or conditional rendering, its associated underlying native resources automatically trigger Dispose(), preventing common memory leaks from an architectural standpoint.
public static (LibVLC, MediaPlayer) CreateMediaPlayer(this Scope scope)
{
var libVlc = new LibVLC();
var mediaPlayer = new MediaPlayer(libVlc);
// When the UI scope is destroyed, underlying unmanaged resources are automatically disposed of synchronously
scope.OnCleanup += () => {
mediaPlayer.Dispose();
libVlc.Dispose();
};
return (libVlc, mediaPlayer);
}Low-level events from multimedia engines (like time updates TimeChanged) usually run on background worker threads. NeHive allows configuring an onSet interceptor during Signal initialization, which automatically redirects data back to the UI dispatcher thread at the source. This ensures thread safety while keeping upstream business logic clean.
var position = new MutSignal<TimeSpan>(TimeSpan.Zero,
onSet: (_, newValue, setter) => Dispatcher.UIThread.Post(() => setter(newValue)));Extracting multimedia metadata (such as parsing large file covers or reading ID3 tags) requires asynchronous IO. NeHive provides the AsyncMemo infrastructure, allowing developers to write asynchronous derived states using a synchronous, declarative topological network, and effortlessly hook them up to the UI's loading states.
var songInfo = uiScope.CreateAsyncMemo<SongInfo?>(async epochScope => {
var index = epochScope.Pull(currentIndex); // Automatically subscribes to and tracks changes in the current playback index
if (index < 0) return null;
var media = new Media(libVlc, playlist.Value[index].FilePath);
await media.Parse(timeout: 5000); // Non-blocking asynchronous parsing
return new SongInfo(media.Meta(MetadataType.Title), ...);
});
// Explicitly consume each state branch of the asynchronous stream in the UI topology (Success, Loading, Error)
Loading<SongInfo?>(new(songInfo)
{
Success = song => Audio(song),
Loading = () => Audio(null),
Error = ex => HTextBlock($"Failed to load: {ex.Message}")
});NeHive discards heavy global redrawing mechanisms. Through built-in control flow primitives, style toggles and conditional branches map directly to fine-grained topologies. When currentIndex changes, only the attributes of the corresponding list item will trigger a targeted redraw, ensuring exceptionally high UI rendering performance.
ForEach<TrackInfo>(new(playlist)
{
ItemTemplate = (track, index) =>
HButton(track.Title,
strStyle: new(() => {
var isActive = index.RxValue == currentIndex.RxValue; // Automatically tracks the currently active item
return $"px-3 py-2 {(isActive ? "bg-sky-100 fg-sky-800" : "bg-transparent")}";
}),
onClick: _ => currentIndex.RxValue = index.Value
)
});| Feature | Traditional MVVM (WPF / Traditional Avalonia) | The NeHive Paradigm |
|---|---|---|
| UI Expression | XAML (Markup language, separated logic) | Pure C# Functional DSL (Declarative code as UI) |
| State Responsiveness | Binding + INotifyPropertyChanged |
Signal automatic dependency tracking & topological updates |
| Update Granularity | Component-level / DataContext-level redraws | Fine-grained, precise updates at the atomic node level |
| Debugging Experience | Runtime black-box; XAML binding errors are hard to debug | Pure C# code; clear call stack; supports direct breakpoints |
| Core Mental Model | Fragmented concepts: Templates, Triggers, Attached Properties, Commands, Converters, etc. | Unified model: Scope + Signal + Effect; everything is built on three primitives |
| Syntax System | Markup language + C# double syntax; split codebase | Pure native C#, where templates and triggers equal anonymous functions + reactivity |
| Data Conversion | Relies on separate Value Converters that must be written, registered, and maintained | Native anonymous functions complete conversions directly with zero extra converter overhead |
| Styling System | Native attribute writing is verbose; combinations are complex and hard to reuse | Tailwind-like atomic strStyle; concise, flexible, and easy to reuse |
| Learning Curve | Numerous concepts and complex rules; high entry barrier | Minimal concepts; mastering the three core primitives covers everything easily |
| Building Paradigm | Forced separation between declarative and imperative styles | Free mixing of declarative and imperative styles to adapt to different business scenarios |
| Module | Description | Status |
|---|---|---|
package/NeHive.Model |
Runtime semantic model layer (Scope / Context) | Preview |
package/NeHive.Reactive |
Fine-grained reactive core (Signal / Effect / Flow) | Preview |
package/NeHive.UI.Avalonia |
Functional UI declarative top-level implementation | Experimental |
package/NeHive.Generator |
Source generators to improve development experience | In Development |
samples |
Collection of sample projects (includes full MusicPlayer implementation) | Actively Maintained |
You can directly install the latest preview versions via NuGet:
# Reactive Core (Required)
dotnet add package NeHive.Reactive --version 0.1.1
# Avalonia UI Integration (For building interfaces)
dotnet add package NeHive.UI.Avalonia --version 0.0.1-alpha
Or search and install via the NuGet Package Manager in Visual Studio:
NeHive.ReactiveNeHive.UI.Avalonia
- A .NET developer longing for the ultimate development experience similar to frontend SolidJS / React.
- Building tools, editors, or dashboard applications driven by complex interactions and high-frequency states.
- Trying to break free from complex MVVM architectures to pursue highly cohesive, easy-to-debug codebases.
- ❌ A drop-in tweak replacement for traditional MVVM frameworks.
- ❌ Pure syntactic sugar made just to replace XAML (it includes a comprehensive reactive runtime architecture).
Warning
NeHive is currently in an early evolutionary stage, and the APIs are frequently iterating and optimizing. Direct use in production environments is not recommended yet. Any constructive Issues and PRs are highly welcome!
This project is open-sourced under the MIT License.

