@@ -56,7 +56,6 @@ public vmTile(IStudy study)
5656 Title = _study . TileTitle ;
5757 Tooltip = _study . TileToolTip ;
5858
59- _localModel . ValueFormatted = "." ;
6059 _localModel . Tooltip = "Waiting for data..." ;
6160
6261 _study . OnCalculated += _study_OnCalculated ;
@@ -94,7 +93,6 @@ public vmTile(IMultiStudy multiStudy)
9493 Title = _multiStudy . TileTitle ;
9594 Tooltip = _multiStudy . TileToolTip ;
9695
97- _localModel . ValueFormatted = "." ;
9896 _localModel . Tooltip = "Waiting for data..." ;
9997
10098 OpenSettingsCommand = new RelayCommand < vmTile > ( OpenSettings ) ;
@@ -159,9 +157,10 @@ private void _study_OnCalculated(object? sender, BaseStudyModel e)
159157 _localModel . copyFrom ( e ) ;
160158 }
161159
162- if ( _localModel . ValueFormatted == "." )
160+
161+ if ( ! _localModel . HasData && ! _localModel . HasError && ! _localModel . IsStale )
163162 _localModel . Tooltip = "Waiting for data..." ;
164- else if ( ! string . IsNullOrEmpty ( _localModel . Tooltip ) )
163+ else if ( ! string . IsNullOrEmpty ( e . Tooltip ) )
165164 _localModel . Tooltip = e . Tooltip ;
166165 else
167166 _localModel . Tooltip = null ;
@@ -172,16 +171,16 @@ private void _study_OnCalculated(object? sender, BaseStudyModel e)
172171
173172 ~ vmTile ( ) { Dispose ( false ) ; }
174173
174+ // In uiUpdaterAction - format on demand:
175175 private void uiUpdaterAction ( )
176176 {
177177 if ( _localModel == null || ! _DATA_AVAILABLE )
178178 return ;
179179 lock ( _lock )
180180 {
181- Value = _localModel . ValueFormatted ;
181+ Value = GetDisplayValue ( _localModel ) ;
182182 ValueTooltip = _localModel . Tooltip ;
183183
184- //update color if set or has changed
185184 if ( _localModel . ValueColor != null )
186185 {
187186 if ( _valueColor == null || _valueColor . ToString ( ) != _localModel . ValueColor )
@@ -191,6 +190,33 @@ private void uiUpdaterAction()
191190 _DATA_AVAILABLE = true ;
192191 }
193192 }
193+ /// <summary>
194+ /// Gets the display value based on model state.
195+ /// Formatting happens here (UI layer) only when needed.
196+ /// </summary>
197+ private static string GetDisplayValue ( BaseStudyModel model )
198+ {
199+ // Priority: Error > Stale > No Data > Normal
200+ if ( model . HasError )
201+ return "Err" ;
202+
203+ if ( model . IsStale )
204+ return "..." ;
205+
206+ if ( ! model . HasData )
207+ return "." ;
208+
209+ // Normal case: format the value
210+ if ( model . CustomFormatter != null )
211+ return model . CustomFormatter ( model . Value ) ;
212+
213+ if ( string . IsNullOrEmpty ( model . Format ) )
214+ return model . Value . ToString ( ) ;
215+
216+ return model . Value . ToString ( model . Format ) ;
217+ }
218+
219+
194220 public void UpdateAllUI ( )
195221 {
196222 _DATA_AVAILABLE = true ;
@@ -341,7 +367,31 @@ protected virtual void Dispose(bool disposing)
341367 }
342368 }
343369 ChildTiles . Clear ( ) ;
370+ ChildTiles = null ;
344371 }
372+
373+ // Dispose the multi-study itself
374+ foreach ( var study in _multiStudy . Studies )
375+ {
376+ try
377+ {
378+ study . StopAsync ( ) ;
379+ study . Dispose ( ) ;
380+ }
381+ catch ( Exception ex )
382+ {
383+ System . Diagnostics . Debug . WriteLine ( $ "Error disposing study: { ex . Message } ") ;
384+ }
385+ }
386+ _multiStudy . Dispose ( ) ;
387+ _multiStudy = null ;
388+ }
389+
390+ // Dispose plugin
391+ if ( _plugin != null )
392+ {
393+ // Note: Plugin disposal handled by PluginManager
394+ _plugin = null ;
345395 }
346396
347397 // Dispose UI updater
0 commit comments