Skip to main content

Value ViewModel

개요

ITK에서는 ViewModel을 줄여 Vm suffix를 사용합니다. 예: ValueVm, DoubleValueVm, MetricValueVm, PowerGeneratorMetricVm

ValueVm 계열은 "값 + 표시 문자열 + 상태(정상/경고/치명)"를 하나의 VM 단위로 다루기 위한 기반 모델입니다. 산업용 화면에서 자주 필요한 단위 표기, 포맷, 임계값 판단을 재사용 가능한 형태로 제공합니다.

ValueVm 계층 구조

ValueVm<T>는 ITK 값 표현의 루트 클래스입니다.

  • Value: 실제 값
  • ValueString: 화면 표시 문자열
  • Status: Normal, Warning, Critical, Error, Unavailable
  • Label, ShortLabel, LabelChar: 화면 밀도별 라벨 표현
  • Prefix, Suffix, AlarmBehavior: 표시/알람 동작 제어

핵심 계층은 아래와 같습니다.

ValueVm<T> : ViewModelBase, IValueVm
├─ FormattableValueVm<T>
│ ├─ TimeSpanValueVm
│ ├─ DateTimeValueVm
│ └─ DateTimeOffsetValueVm
├─ NumericValueVm<T>
│ ├─ IntValueVm
│ ├─ LongValueVm
│ ├─ DecimalValueVm
│ ├─ FloatValueVm
│ └─ DoubleValueVm
│ └─ MetricValueVm
└─ StringValueVm

ValueVm을 상속받아 구체화된 클래스와 역할

클래스역할
StringValueVm문자열 값 표현. 포맷 문자열 기반 텍스트 조합에 사용
TimeSpanValueVmTimeSpan 표시 전용. 운영 시간/가동 시간 표시에 적합
DateTimeValueVmDateTime 표시 전용. DateTimeKind.Unspecified를 경고 상태로 처리
DateTimeOffsetValueVm타임존 정보를 포함한 시각 표시
IntValueVm정수 수치 값 + 단위 표시
LongValueVm대용량 정수 수치 값 + 단위 표시
DecimalValueVm정밀 소수(예: 금액/누적량) 값 + 단위 표시
FloatValueVm부동소수 값 + 단위 표시 + 정밀도 연산자
DoubleValueVm일반 수치 값 표현의 기본 선택지. 단위/포맷/상태 평가/정밀도 처리
MetricValueVmDoubleValueVm 확장형. Min/Max 및 Warning/Critical 임계값으로 상태 자동 평가

PowerGenerator 예제로 보는 사용 패턴

PowerGenerator 샘플은 동일한 도메인 데이터를 두 방식으로 보여줍니다.

  • PowerGeneratorVm: DoubleValueVm + 사용자 정의 상태 평가 함수
  • PowerGeneratorMetricVm: MetricValueVm + 선언형 Threshold 설정

ValueVm은 View에 어떻게 표시되는가

ValueVm 계열은 단순한 데이터 구조가 아니라, View가 바로 바인딩할 수 있는 표시 단위입니다. 예를 들어 PowerGeneratorMetricVm은 전압, 전류, 출력, 온도 같은 값을 각각 MetricValueVm으로 보유하고 있고, 게이지 패널 VM은 이 값을 다시 게이지 VM의 Metric 속성에 연결합니다.

public sealed class GC_RING01DemosPanelVm : ContentPanelVm
{
private readonly PowerGeneratorMetricVm _metrics;

public GC_RING01DemosPanelVm(PowerGeneratorMetricVm metrics)
{
_metrics = metrics;

var gauge1 = new GCLRING01GaugeVm()
{
Metric = _metrics.ActivePower,
Accent = ItkThemeAccent.Default,
};

var gauge2 = new GCLRING01GaugeVm()
{
Metric = _metrics.EngineSpeed,
Accent = ItkThemeAccent.Strong,
};

var gauge3 = new GCLRING01GaugeVm()
{
Metric = _metrics.EngineTemperature,
Accent = ItkThemeAccent.A,
};
}
}

이 구조에서 중요한 점은 다음과 같습니다.

  • PowerGeneratorMetricVm은 도메인 값과 임계값 규칙을 소유합니다.
  • GCLRING01GaugeVm은 어떤 MetricValueVm을 표시할지만 선택합니다.
  • 실제 View는 게이지 VM에 바인딩되어 Label, ValueString, UnitString, Status 같은 표시 정보를 사용합니다.
  • 즉, 값 판단 로직은 ValueVm 쪽에 남고, View는 그 결과를 일관된 방식으로 렌더링합니다.

또한 ITK의 UI 요소들은 Accent와 같은 시각적 속성, 라인 스타일, 라벨 배치, 장식 베젤 같은 표현 속성을 함께 가질 수 있습니다. 이런 속성들은 단순한 색상 하드코딩이 아니라 ITK 테마 시스템과 연결되어 동작하므로, 애플리케이션 개발자는 값 처리 로직과 화면 꾸밈 로직을 분리한 상태에서도 화면 전체의 시각적 일관성을 유지할 수 있습니다. 즉 MetricValueVm은 "무엇을 표시할 것인가"를 설명하고, 게이지/카드/리스트 같은 UI VM은 Accent와 테마 규칙을 통해 "어떻게 보일 것인가"를 결정합니다.

아래 이미지는 GC_RING01DemosPanelVmActivePower, EngineSpeed, EngineTemperature를 각각 게이지에 바인딩한 결과입니다.

Gauge panel demo showing MetricValueVm instances bound to circular gauge views

이 예제는 ValueVm 계열이 단순히 테이블 문자열을 만들기 위한 객체가 아니라, 카드, 리스트, 게이지 같은 다양한 View에 동일한 방식으로 재사용될 수 있는 표시 모델이라는 점을 보여줍니다.

1) 함수 기반 상태 평가 (PowerGeneratorVm)

_outputVoltage = new DoubleValueVm("OutputVoltage", NumericUnit.Voltage_Volt, "F2", GetOutputVoltageStatus)
{
Label = "Output Voltage",
ShortLabel = "Vout",
LabelChar = "Vo",
};

private ValueStatus GetOutputVoltageStatus(double voltage)
{
if (voltage > _specification.VoltageWarningLow && voltage < _specification.VoltageWarningHigh)
return ValueStatus.Normal;
else if (voltage > _specification.VoltageCriticalLow && voltage < _specification.VoltageCriticalHigh)
return ValueStatus.Warning;
else
return ValueStatus.Critical;
}

장점:

  • 도메인 규칙이 복잡할 때 유연함
  • 항목별로 서로 다른 판단 로직을 넣기 쉬움

2) 임계값 기반 상태 평가 (PowerGeneratorMetricVm)

_outputVoltage = new MetricValueVm(
"OutputVoltage", _specification.VoltageCriticalLow - 5, _specification.VoltageCriticalHigh + 5,
NumericUnit.Voltage_Volt, "F2", new RoundingOperator(2))
{
Label = "Output Voltage",
HighCriticalThreshold = _specification.VoltageCriticalHigh,
HighWarningThreshold = _specification.VoltageWarningHigh,
LowCriticalThreshold = _specification.VoltageCriticalLow,
LowWarningThreshold = _specification.VoltageWarningLow,
};

장점:

  • 설정이 선언적이라 읽기 쉬움
  • 여러 수치 항목에 동일 패턴을 빠르게 적용 가능

3) 실시간 업데이트와 UI 스레드 반영

두 샘플 모두 시뮬레이터 이벤트를 받아 Value만 갱신하면, 각 ValueVmValueStringStatus를 동기화합니다.

private void UpdateValues(GeneratorDataEventArgs e)
{
OutputVoltage.Value = e.OutputVoltage;
OutputCurrent.Value = e.OutputCurrent;
Frequency.Value = e.Frequency;
RunningHours.Value = TimeSpan.FromSeconds(e.RunningHours);
}

게이지 패널까지 포함해 보면 데이터 흐름은 아래처럼 읽을 수 있습니다.

PowerGeneratorSimulator
-> PowerGeneratorMetricVm.UpdateValues(...)
-> MetricValueVm.Value / Status / ValueString 갱신
-> GCLRING01GaugeVm.Metric 이 변경 결과를 참조
-> Gauge View가 원형 게이지, 숫자, 단위, 색상 상태를 화면에 표시

이 흐름 덕분에 애플리케이션 개발자는 화면마다 별도의 값 포맷팅 코드나 상태 색상 계산 코드를 중복 작성하지 않아도 됩니다. 필요한 것은 적절한 ValueVm을 만들고, 해당 값을 소비하는 ViewModel (GaugeVm, TableItemVm, CardVm 등)에 연결하는 일입니다.

언제 어떤 ValueVm을 선택하면 좋은가

  • 단순 수치 + 단위 표시: DoubleValueVm
  • 수치 + 임계값 경보: MetricValueVm
  • 시간 표시: TimeSpanValueVm, DateTimeValueVm, DateTimeOffsetValueVm
  • 텍스트 상태 표시: StringValueVm

요약

ITK의 ValueVm 계열은 값 표시를 "UI 데이터 바인딩 단위"로 표준화해 반복 코드를 줄여줍니다. PowerGeneratorVm처럼 함수 기반으로 시작한 뒤, 패턴이 안정되면 PowerGeneratorMetricVm처럼 임계값 기반 MetricValueVm으로 정리하는 흐름이 실무에서 효율적입니다.