iconDreamine

체험

Dreamine MVVM을 브라우저에서 직접 눌러보고, WPF/WinForms/MAUI는 실제 실행 이미지나 동영상으로 확인합니다.

전구 — 버튼 & 체크박스

버튼(커맨드)과 체크박스(양방향 바인딩)가 같은 상태를 조작합니다. 로직은 Event, 상태는 Model, 노출은 ViewModel — Dreamine의 3분할 그대로입니다.

OFF
토글 0회
이 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가 카운트를 올리고 로그를 남깁니다.

클릭 0
이 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 바인딩.

선택: Cherry
이 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에 바인딩해 코드에서도 펼침/접힘을 제어합니다.

펼치기 / 접기
내부에는 어떤 콘텐츠도 배치할 수 있습니다. IsExpanded = True
이 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)되는 숫자 입력. 슬라이더/숫자 어느 쪽으로 바꿔도 값이 동기화됩니다.

값: 50
이 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으로 초기화합니다. 로그가 자동으로 쌓입니다.

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. 읽기 전용 테이블에 장비 상태를 표시합니다.

NoNameStatus
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로 로드 실패 시 대체 이미지도 지정 가능합니다.

이미지 클릭 0
이 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++;