Value ViewModel
개요
ITK에서는 ViewModel을 줄여 Vm suffix를 사용합니다.
예: ValueVm, DoubleValueVm, MetricValueVm, PowerGeneratorMetricVm
ValueVm 계열은 "값 + 표시 문자열 + 상태(정상/경고/치명)"를 하나의 VM 단위로 다루기 위한 기반 모델입니다.
산업용 화면에서 자주 필요한 단위 표기, 포맷, 임계값 판단을 재사용 가능한 형태로 제공합니다.
ValueVm 계층 구조
ValueVm<T>는 ITK 값 표현의 루트 클래스입니다.
Value: 실제 값ValueString: 화면 표시 문자열Status:Normal,Warning,Critical,Error,UnavailableLabel,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 | 문자열 값 표현. 포맷 문자열 기반 텍스트 조합에 사용 |
TimeSpanValueVm | TimeSpan 표시 전용. 운영 시간/가동 시간 표시에 적합 |
DateTimeValueVm | DateTime 표시 전용. DateTimeKind.Unspecified를 경고 상태로 처리 |
DateTimeOffsetValueVm | 타임존 정보를 포함한 시각 표시 |
IntValueVm | 정수 수치 값 + 단위 표시 |
LongValueVm | 대용량 정수 수치 값 + 단위 표시 |
DecimalValueVm | 정밀 소수(예: 금액/누적량) 값 + 단위 표시 |
FloatValueVm | 부동소수 값 + 단위 표시 + 정밀도 연산자 |
DoubleValueVm | 일반 수치 값 표현의 기본 선택지. 단위/포맷/상태 평가/정밀도 처리 |
MetricValueVm | DoubleValueVm 확장형. 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_RING01DemosPanelVm이 ActivePower, EngineSpeed, EngineTemperature를 각각 게이지에 바인딩한 결과입니다.

이 예제는 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만 갱신하면, 각 ValueVm이 ValueString과 Status를 동기화합니다.
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으로 정리하는 흐름이 실무에서 효율적입니다.