Playground
Try Dreamine MVVM in the browser; review WPF/WinForms/MAUI through real screenshots or videos.
Light Bulb — Button & Checkbox
A button (command) and a checkbox (two-way binding) drive the same state. Logic in Event, state in Model, exposure in ViewModel.
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineLightBulb IsOn="@Bulb.IsOn" Diameter="120" />
<DreamineButton Variant="DreamineButtonVariant.Primary" OnClick="Bulb.Toggle">Toggle</DreamineButton>
<DreamineCheckBox @bind-Checked="Bulb.IsOn">Power</DreamineCheckBox>
<span>@Bulb.StatusText · toggled @Bulb.ToggleCount times</span>public sealed class LightBulbModel { public bool IsOn; public int ToggleCount; }
public sealed class LightBulbEvent
{
private readonly LightBulbModel _m;
public LightBulbEvent(LightBulbModel m) => _m = m;
public void Toggle() { _m.IsOn = !_m.IsOn; _m.ToggleCount++; }
}
public sealed class LightBulbViewModel : ViewModelBase
{
public bool IsOn { get; set; }
public int ToggleCount { get; }
public string StatusText => IsOn ? "ON" : "OFF";
}Button — DreamineButton
A command-bound button. Each click increments the count and appends a log via the Event.
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineButton Variant="DreamineButtonVariant.Primary" OnClick="Vm.ClickMe">Primary</DreamineButton>
<DreamineButton OnClick="Vm.ClickMe">Secondary</DreamineButton>
<DreamineButton Variant="DreamineButtonVariant.Danger" OnClick="Vm.ClickMe">Danger</DreamineButton>
<span>Clicks @Vm.ClickCount</span>
@foreach (var line in Vm.ActivityLog) { <li>@line</li> }// Shared ViewModel (Dreamine Source Generator)
[DreamineProperty] private int _clickCount;
public ObservableCollection<string> ActivityLog { get; } = new();
[DreamineCommand]
private void ClickMe()
{
ClickCount++;
ActivityLog.Insert(0, $"[{DateTime.Now:HH:mm:ss}] Clicked ({ClickCount})");
}CheckBox — DreamineCheckBox
IsChecked two-way binding. The last item is disabled (IsEnabled=False).
Check1 = True · Check2 = False
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineCheckBox @bind-Checked="Vm.Check1">Check 1</DreamineCheckBox>
<DreamineCheckBox @bind-Checked="Vm.Check2">Check 2</DreamineCheckBox>
<DreamineCheckBox @bind-Checked="Vm.Check3" Disabled="true">Check 3</DreamineCheckBox>
<p>Check1 = @Vm.Check1 · Check2 = @Vm.Check2</p>[DreamineProperty] private bool _check1 = true;
[DreamineProperty] private bool _check2;
[DreamineProperty] private bool _check3;RadioButton — DreamineRadioButton
Radios sharing a GroupName; selection passes the value via RelayCommand<string>.
Selected: Option A
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
@foreach (var opt in new[] { "Option A", "Option B", "Option C" })
{
<DreamineRadioButton Name="grp" Value="@opt"
SelectedValue="@Vm.SelectedRadio"
SelectedValueChanged="Vm.SelectRadio">@opt</DreamineRadioButton>
}
<p>Selected: @Vm.SelectedRadio</p>[DreamineProperty] private string _selectedRadio = "Option A";
[DreamineCommand]
private void SelectRadio(string option) => SelectedRadio = option;CheckLed — DreamineCheckLed
Dreamine's signature LED indicator. Bind IsOn / IsPulse (great for equipment status).
IsOn = True · IsPulse = False
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineCheckLed IsOn="Vm.LedIsOn" IsPulse="Vm.LedIsPulse" Diameter="34" />
<DreamineButton OnClick="Vm.ToggleLed">ON / OFF</DreamineButton>
<DreamineButton OnClick="Vm.TogglePulse">Pulse</DreamineButton>
<p>IsOn = @Vm.LedIsOn · IsPulse = @Vm.LedIsPulse</p>[DreamineProperty] private bool _ledIsOn = true;
[DreamineProperty] private bool _ledIsPulse;
[DreamineCommand] private void ToggleLed() => LedIsOn = !LedIsOn;
[DreamineCommand] private void TogglePulse() => LedIsPulse = !LedIsPulse;TextBox / PasswordBox — DreamineTextBox
Input controls with Hint (placeholder). Clear via command.
Value:
Length: 0
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineTextBox @bind-Value="Vm.TextInput" Hint="Type here..."
OnFocus="() => _showKeyboard = true" />
<DreamineButton Size="DreamineButtonSize.Small" OnClick="Vm.ClearText">Clear</DreamineButton>
<p>Value: @Vm.TextInput</p>
@* 가상 키보드는 대상 텍스트박스 바로 아래에 표시 — 시선이 튀지 않게. *@
@if (_showKeyboard)
{
<DreamineVirtualKeyboard IsVisible="_showKeyboard"
Value="@Vm.TextInput"
ValueChanged="v => Vm.TextInput = v"
OnEnter="() => _showKeyboard = false" />
}
<DreamineTextBox @bind-Value="Vm.Password" IsPassword="true" Hint="Password..." />
<DreamineButton Size="DreamineButtonSize.Small" OnClick="Vm.ClearPassword">Clear</DreamineButton>
<p>Length: @Vm.Password.Length</p>
@code { private bool _showKeyboard; }[DreamineProperty] private string _textInput = string.Empty;
[DreamineProperty] private string _password = string.Empty;
[DreamineCommand] private void ClearText() => TextInput = string.Empty;
[DreamineCommand] private void ClearPassword() => Password = string.Empty;ComboBox — DreamineComboBox
ItemsSource / SelectedItem binding.
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineComboBox Items="Vm.FruitItems" @bind-SelectedItem="Vm.SelectedFruit" />
<span>Selected: @Vm.SelectedFruit</span>public string[] FruitItems { get; } =
{ "Apple", "Banana", "Cherry", "Grape", "Mango", "Melon" };
[DreamineProperty] private string _selectedFruit = "Cherry";Expander — DreamineExpander
Bind IsExpanded to the VM to control expand/collapse from code too.
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineExpander Header="Expand / Collapse" @bind-IsExpanded="Vm.IsExpanded">
Any content can go here. IsExpanded = @Vm.IsExpanded
</DreamineExpander>[DreamineProperty] private bool _isExpanded = true;
[DreamineCommand] private void ToggleExpand() => IsExpanded = !IsExpanded;Numeric — NumericRangeBehavior
Numeric input clamped to 0–100. Slider and number stay in sync.
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineNumericSlider @bind-Value="Vm.NumericInput" Min="0" Max="100" />
<span>Value: @Vm.NumericInput</span>private double _numericInput = 50;
public double NumericInput
{
get => _numericInput;
set { _numericInput = Math.Clamp(value, 0, 100); OnPropertyChanged(); }
}ListBox — DreamineListBox
Select (click) + run a command on double-click (activation).
- Apple
- Banana
- Cherry
- Grape
- Mango
- Melon
Selected: Cherry · (double-click an item)
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineListBox Items="Vm.FruitItems"
@bind-SelectedItem="Vm.SelectedFruit"
OnActivate="Vm.ActivateListItem" />
<p>Selected: @Vm.SelectedFruit · @Vm.ListActivated</p>public string[] FruitItems { get; } =
{ "Apple", "Banana", "Cherry", "Grape", "Mango", "Melon" };
[DreamineProperty] private string _selectedFruit = "Cherry";
[DreamineProperty] private string _listActivated = "(double-click an item)";
[DreamineCommand]
private void ActivateListItem(string item) => ListActivated = $"Activated: {item}";Counter — Increment / Reset
The SampleCrossUi counter demo. Increment goes through a service, Reset zeroes the count, and logs accumulate automatically.
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<span class="dw-counter-value">@Vm.Count</span>
<DreamineButton Variant="DreamineButtonVariant.Primary" OnClick="Vm.Increment">Increment</DreamineButton>
<DreamineButton OnClick="Vm.ResetCounter">Reset</DreamineButton>
@foreach (var line in Vm.CounterLogs) { <li>@line</li> }[DreamineProperty] private int _count;
public ObservableCollection<string> CounterLogs { get; } = new();
[DreamineCommand]
private void Increment()
{
Count++;
CounterLogs.Insert(0, $"[{DateTime.Now:HH:mm:ss}] Incremented → {Count}");
}
[DreamineCommand]
private void ResetCounter()
{
Count = 0;
CounterLogs.Insert(0, $"[{DateTime.Now:HH:mm:ss}] Counter reset.");
}DataGrid — DreamineDataGrid
ItemsSource binding + ClickToDeselect Behavior. Displays equipment status in a read-only table.
| No | Name | Status |
|---|---|---|
| 1 | Device A | Running |
| 2 | Device B | Stopped |
| 3 | Device C | Running |
| 4 | Device D | Error |
Selected: —
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor *@
<DreamineDataGrid TItem="GridRow" Items="Vm.GridRows" @bind-SelectedItem="Vm.SelectedRow">
<HeaderContent><th>No</th><th>Name</th><th>Status</th></HeaderContent>
<RowContent>
<td>@context.No</td><td>@context.Name</td><td>@context.Status</td>
</RowContent>
</DreamineDataGrid>public ObservableCollection<GridRow> GridRows { get; } = new()
{
new() { No = 1, Name = "Device A", Status = "Running" },
new() { No = 2, Name = "Device B", Status = "Stopped" },
new() { No = 3, Name = "Device C", Status = "Running" },
new() { No = 4, Name = "Device D", Status = "Error" },
};
[DreamineProperty] private GridRow? _selectedRow;TimeSpinner — DreamineTimeSpinner
Adjust hours, minutes, seconds with ▲▼ buttons. WPF also supports scroll wheel and keyboard.
Time: 09:30:00
Show the code behind this Live demo
<div class="dw-timespinner">
<div>
<button @onclick="@(() => Vm.Hours++)">▲</button>
<input type="number" min="0" max="23" @bind="Vm.Hours" />
<button @onclick="@(() => Vm.Hours--)">▼</button>
</div>
<span>:</span>
<!-- Minutes and seconds use the same structure. -->
</div>
<p>Time: @Vm.TimeDisplay</p>[DreamineProperty] private int _hours = 9;
[DreamineProperty] private int _minutes = 30;
[DreamineProperty] private int _seconds;
public string TimeDisplay => $"{Hours:D2}:{Minutes:D2}:{Seconds:D2}";Image — DreamineImage
CornerRadius for rounded corners, ClickCommand for click events. FallbackSource provides a fallback on load failure.
Show the code behind this Live demo
<div class="dw-image-demo" @onclick="Vm.ClickImage">
<svg viewBox="0 0 100 100" width="80" height="80">
<circle cx="50" cy="50" r="50" fill="#1E90FF"/>
<circle cx="50" cy="50" r="22" fill="#fff"/>
</svg>
</div>
<span>Image clicks @Vm.ImageClickCount</span>[DreamineProperty] private int _imageClickCount;
[DreamineCommand]
private void ClickImage() => ImageClickCount++;Popup — MessageBox & BlinkPopup
Message box and blinking popup. Show an alarm-style modal whose colors alternate, with optional auto-close countdown. The result is awaited.
Last result: —
Show the code behind this Live demo
@* @using Dreamine.UI.Blazor
@inject DreamineDialogService Dialog
페이지 어딘가에 <DreamineDialogHost /> 를 한 번 배치해야 합니다. *@
<DreamineButton OnClick="ShowMessageBox">DreamineMessageBox (5s)</DreamineButton>
<DreamineButton Variant="DreamineButtonVariant.Danger" OnClick="ShowAlarm">ALARM (blink)</DreamineButton>
@code {
private async Task ShowMessageBox()
{
var r = await Dialog.ShowMessageBoxAsync(
"Message box demo.", "MessageBox", autoClickDelaySeconds: 5);
}
private async Task ShowAlarm()
{
var r = await Dialog.ShowBlinkAsync(new BlinkPopupOptions
{
Title = "⚠ ALARM", Message = "Equipment fault detected.",
UseBlink = true, BlinkIntervalMs = 400,
Color1 = "#B41E1E", Color2 = "#500A0A",
ForegroundColor = "#FFD700", OkText = "OK", CancelText = "Cancel"
});
}
}// DreamineDialogService는 DI에 Scoped로 등록합니다.
// builder.Services.AddScoped<DreamineDialogService>();
// WPF의 IPopupService / WinForms·MAUI의 DreamineMessageBox·DreamineBlinkPopup과
// 같은 역할을 하며, Blazor에서는 <DreamineDialogHost /> 오버레이가 실제로 그립니다.
DreamineDialogResult result = await Dialog.ShowMessageBoxAsync(message, title);