체험
Dreamine MVVM을 브라우저에서 직접 눌러보고, WPF/WinForms/MAUI는 실제 실행 이미지나 동영상으로 확인합니다.
전구 — 버튼 & 체크박스
버튼(커맨드)과 체크박스(양방향 바인딩)가 같은 상태를 조작합니다. 로직은 Event, 상태는 Model, 노출은 ViewModel — Dreamine의 3분할 그대로입니다.
이 Live 데모의 실제 코드 보기
@* @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
커맨드에 바인딩된 버튼. 클릭할 때마다 Event가 카운트를 올리고 로그를 남깁니다.
이 Live 데모의 실제 코드 보기
@* @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 양방향 바인딩. 마지막 항목은 IsEnabled=False로 비활성 상태입니다.
Check1 = True · Check2 = False
이 Live 데모의 실제 코드 보기
@* @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
같은 GroupName으로 묶인 라디오. 선택 시 RelayCommand<string>로 값을 전달합니다.
선택: Option A
이 Live 데모의 실제 코드 보기
@* @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 시그니처 LED 인디케이터. IsOn / IsPulse 를 바인딩합니다 (장비 상태 표시용).
IsOn = True · IsPulse = False
이 Live 데모의 실제 코드 보기
@* @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
Hint(placeholder) 지원 입력 컨트롤. Clear 커맨드로 값을 비웁니다.
값:
길이: 0
이 Live 데모의 실제 코드 보기
@* @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 바인딩.
이 Live 데모의 실제 코드 보기
@* @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
IsExpanded를 VM에 바인딩해 코드에서도 펼침/접힘을 제어합니다.
이 Live 데모의 실제 코드 보기
@* @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
0~100 범위로 자동 보정(Clamp)되는 숫자 입력. 슬라이더/숫자 어느 쪽으로 바꿔도 값이 동기화됩니다.
이 Live 데모의 실제 코드 보기
@* @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
선택(클릭) + 더블클릭 시 커맨드 실행(활성화).
- Apple
- Banana
- Cherry
- Grape
- Mango
- Melon
선택: Cherry · (double-click an item)
이 Live 데모의 실제 코드 보기
@* @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
SampleCrossUi의 카운터 데모. Increment는 서비스를 거쳐 값을 올리고, Reset은 0으로 초기화합니다. 로그가 자동으로 쌓입니다.
이 Live 데모의 실제 코드 보기
@* @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 바인딩 + ClickToDeselect Behavior. 읽기 전용 테이블에 장비 상태를 표시합니다.
| No | Name | Status |
|---|---|---|
| 1 | Device A | Running |
| 2 | Device B | Stopped |
| 3 | Device C | Running |
| 4 | Device D | Error |
선택: —
이 Live 데모의 실제 코드 보기
@* @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
시:분:초를 ▲▼ 버튼으로 조절합니다. WPF에서는 스크롤 휠과 키보드도 지원합니다.
시각: 09:30:00
이 Live 데모의 실제 코드 보기
<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로 둥근 모서리, ClickCommand로 클릭 이벤트를 바인딩합니다. FallbackSource로 로드 실패 시 대체 이미지도 지정 가능합니다.
이 Live 데모의 실제 코드 보기
<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
메시지 박스와 점멸(Blink) 팝업. 설비 알람처럼 색이 번갈아 깜빡이는 모달을 띄우고, 자동 닫힘(카운트다운)도 지원합니다. 결과는 await로 받습니다.
Last result: —
이 Live 데모의 실제 코드 보기
@* @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);