1 using System; 2 using System.ComponentModel; 3 using System.Linq; 4 using System.Reactive.Disposables; 5 using System.Reactive.Linq; 6 using Reactive.Bindings; 7 using Reactive.Bindings.Extensions; 8 using TrainEditor2.Models.Panels; 9 using TrainEditor2.ViewModels.Others; 10 11 namespace TrainEditor2.ViewModels.Panels 12 { 13 internal class PanelViewModel : BaseViewModel 14 { 15 internal ReadOnlyReactivePropertySlim<ThisViewModel> This 16 { 17 get; 18 } 19 20 internal ReactiveProperty<TreeViewItemViewModel> TreeItem 21 { 22 get; 23 } 24 25 internal ReactiveProperty<TreeViewItemViewModel> SelectedTreeItem 26 { 27 get; 28 } 29 30 internal ReadOnlyReactiveCollection<ListViewColumnHeaderViewModel> ListColumns 31 { 32 get; 33 } 34 35 internal ReadOnlyReactiveCollection<ListViewItemViewModel> ListItems 36 { 37 get; 38 } 39 40 internal ReactiveProperty<ListViewItemViewModel> SelectedListItem 41 { 42 get; 43 } 44 45 internal ReadOnlyReactivePropertySlim<ScreenViewModel> SelectedScreen 46 { 47 get; 48 } 49 50 internal ReadOnlyReactivePropertySlim<PilotLampElementViewModel> SelectedPilotLamp 51 { 52 get; 53 } 54 55 internal ReadOnlyReactivePropertySlim<NeedleElementViewModel> SelectedNeedle 56 { 57 get; 58 } 59 60 internal ReadOnlyReactivePropertySlim<DigitalNumberElementViewModel> SelectedDigitalNumber 61 { 62 get; 63 } 64 65 internal ReadOnlyReactivePropertySlim<DigitalGaugeElementViewModel> SelectedDigitalGauge 66 { 67 get; 68 } 69 70 internal ReadOnlyReactivePropertySlim<LinearGaugeElementViewModel> SelectedLinearGauge 71 { 72 get; 73 } 74 75 internal ReadOnlyReactivePropertySlim<TimetableElementViewModel> SelectedTimetable 76 { 77 get; 78 } 79 80 internal ReadOnlyReactivePropertySlim<TouchElementViewModel> SelectedTouch 81 { 82 get; 83 } 84 85 internal ReactiveCommand AddScreen 86 { 87 get; 88 } 89 90 internal ReactiveCommand AddPilotLamp 91 { 92 get; 93 } 94 95 internal ReactiveCommand AddNeedle 96 { 97 get; 98 } 99 100 internal ReactiveCommand AddDigitalNumber 101 { 102 get; 103 } 104 105 internal ReactiveCommand AddDigitalGauge 106 { 107 get; 108 } 109 110 internal ReactiveCommand AddLinearGauge 111 { 112 get; 113 } 114 115 internal ReactiveCommand AddTimetable 116 { 117 get; 118 } 119 120 internal ReactiveCommand AddTouch 121 { 122 get; 123 } 124 125 internal ReactiveCommand CopyScreen 126 { 127 get; 128 } 129 130 internal ReactiveCommand CopyPilotLamp 131 { 132 get; 133 } 134 135 internal ReactiveCommand CopyNeedle 136 { 137 get; 138 } 139 140 internal ReactiveCommand CopyDigitalNumber 141 { 142 get; 143 } 144 145 internal ReactiveCommand CopyDigitalGauge 146 { 147 get; 148 } 149 150 internal ReactiveCommand CopyLinearGauge 151 { 152 get; 153 } 154 155 internal ReactiveCommand CopyTimetable 156 { 157 get; 158 } 159 160 internal ReactiveCommand CopyTouch 161 { 162 get; 163 } 164 165 internal ReactiveCommand RemoveScreen 166 { 167 get; 168 } 169 170 internal ReactiveCommand RemovePilotLamp 171 { 172 get; 173 } 174 175 internal ReactiveCommand RemoveNeedle 176 { 177 get; 178 } 179 180 internal ReactiveCommand RemoveDigitalNumber 181 { 182 get; 183 } 184 185 internal ReactiveCommand RemoveDigitalGauge 186 { 187 get; 188 } 189 190 internal ReactiveCommand RemoveLinearGauge 191 { 192 get; 193 } 194 195 internal ReactiveCommand RemoveTimetable 196 { 197 get; 198 } 199 200 internal ReactiveCommand RemoveTouch 201 { 202 get; 203 } 204 PanelViewModel(Panel panel)205 internal PanelViewModel(Panel panel) 206 { 207 CompositeDisposable treeItemDisposable = new CompositeDisposable(); 208 CompositeDisposable listItemDisposable = new CompositeDisposable(); 209 210 This = panel 211 .ObserveProperty(x => x.This) 212 .Do(_ => This?.Value.Dispose()) 213 .Select(x => new ThisViewModel(x)) 214 .ToReadOnlyReactivePropertySlim() 215 .AddTo(disposable); 216 217 TreeItem = panel 218 .ObserveProperty(x => x.TreeItem) 219 .Do(_ => TreeItem?.Value.Dispose()) 220 .Select(x => new TreeViewItemViewModel(x)) 221 .ToReactiveProperty() 222 .AddTo(disposable); 223 224 TreeItem.Subscribe(x => 225 { 226 treeItemDisposable.Dispose(); 227 treeItemDisposable = new CompositeDisposable(); 228 229 x.PropertyChangedAsObservable() 230 .ToReadOnlyReactivePropertySlim(mode: ReactivePropertyMode.None) 231 .Subscribe(_ => TreeItem.ForceNotify()) 232 .AddTo(treeItemDisposable); 233 }) 234 .AddTo(disposable); 235 236 SelectedTreeItem = panel 237 .ToReactivePropertyAsSynchronized( 238 x => x.SelectedTreeItem, 239 x => TreeItem.Value.SearchViewModel(x), 240 x => x?.Model 241 ) 242 .AddTo(disposable); 243 244 ListColumns = panel.ListColumns 245 .ToReadOnlyReactiveCollection(x => new ListViewColumnHeaderViewModel(x)) 246 .AddTo(disposable); 247 248 ListItems = panel.ListItems 249 .ToReadOnlyReactiveCollection(x => new ListViewItemViewModel(x)) 250 .AddTo(disposable); 251 252 SelectedListItem = panel 253 .ToReactivePropertyAsSynchronized( 254 x => x.SelectedListItem, 255 x => ListItems.FirstOrDefault(y => y.Model == x), 256 x => x?.Model 257 ) 258 .AddTo(disposable); 259 260 SelectedTreeItem 261 .Subscribe(_ => 262 { 263 SelectedListItem.Value = null; 264 panel.CreateListColumns(); 265 panel.CreateListItems(); 266 }) 267 .AddTo(disposable); 268 269 SelectedListItem 270 .Where(x => x != null) 271 .Subscribe(x => 272 { 273 listItemDisposable.Dispose(); 274 listItemDisposable = new CompositeDisposable(); 275 276 CompositeDisposable tagDisposable = new CompositeDisposable(); 277 278 x.Tag 279 .OfType<INotifyPropertyChanged>() 280 .Subscribe(y => 281 { 282 tagDisposable.Dispose(); 283 tagDisposable = new CompositeDisposable(); 284 285 CompositeDisposable subjectDisposable = new CompositeDisposable(); 286 287 y.PropertyChangedAsObservable() 288 .Subscribe(_ => panel.UpdateListItem(x.Model)) 289 .AddTo(tagDisposable); 290 291 Screen screen = y as Screen; 292 PilotLampElement pilotLamp = y as PilotLampElement; 293 NeedleElement needle = y as NeedleElement; 294 DigitalNumberElement digitalNumber = y as DigitalNumberElement; 295 DigitalGaugeElement digitalGauge = y as DigitalGaugeElement; 296 LinearGaugeElement linearGauge = y as LinearGaugeElement; 297 298 screen?.ObserveProperty(z => z.Number) 299 .Select(_ => TreeItem.Value.Children[1].Children.FirstOrDefault(z => z.Tag.Value == screen)) 300 .Where(z => z != null) 301 .Subscribe(z => panel.RenameScreenTreeItem(z.Model)) 302 .AddTo(tagDisposable); 303 304 pilotLamp?.ObserveProperty(z => z.Subject) 305 .Subscribe(z => 306 { 307 subjectDisposable.Dispose(); 308 subjectDisposable = new CompositeDisposable(); 309 310 z.PropertyChangedAsObservable() 311 .Subscribe(_ => panel.UpdateListItem(x.Model)) 312 .AddTo(subjectDisposable); 313 }) 314 .AddTo(tagDisposable); 315 316 needle?.ObserveProperty(z => z.Subject) 317 .Subscribe(z => 318 { 319 subjectDisposable.Dispose(); 320 subjectDisposable = new CompositeDisposable(); 321 322 z.PropertyChangedAsObservable() 323 .Subscribe(_ => panel.UpdateListItem(x.Model)) 324 .AddTo(subjectDisposable); 325 }) 326 .AddTo(tagDisposable); 327 328 digitalNumber?.ObserveProperty(z => z.Subject) 329 .Subscribe(z => 330 { 331 subjectDisposable.Dispose(); 332 subjectDisposable = new CompositeDisposable(); 333 334 z.PropertyChangedAsObservable() 335 .Subscribe(_ => panel.UpdateListItem(x.Model)) 336 .AddTo(subjectDisposable); 337 }) 338 .AddTo(tagDisposable); 339 340 digitalGauge?.ObserveProperty(z => z.Subject) 341 .Subscribe(z => 342 { 343 subjectDisposable.Dispose(); 344 subjectDisposable = new CompositeDisposable(); 345 346 z.PropertyChangedAsObservable() 347 .Subscribe(_ => panel.UpdateListItem(x.Model)) 348 .AddTo(subjectDisposable); 349 }) 350 .AddTo(tagDisposable); 351 352 linearGauge?.ObserveProperty(z => z.Subject) 353 .Subscribe(z => 354 { 355 subjectDisposable.Dispose(); 356 subjectDisposable = new CompositeDisposable(); 357 358 z.PropertyChangedAsObservable() 359 .Subscribe(_ => panel.UpdateListItem(x.Model)) 360 .AddTo(subjectDisposable); 361 }) 362 .AddTo(tagDisposable); 363 364 subjectDisposable.AddTo(tagDisposable); 365 }) 366 .AddTo(listItemDisposable); 367 368 tagDisposable.AddTo(listItemDisposable); 369 }) 370 .AddTo(disposable); 371 372 SelectedScreen = SelectedListItem 373 .Select(x => x?.Tag.Value as Screen) 374 .Do(_ => SelectedScreen?.Value?.Dispose()) 375 .Select(x => x != null ? new ScreenViewModel(x, panel.Screens.Where(y => y != x)) : null) 376 .ToReadOnlyReactivePropertySlim() 377 .AddTo(disposable); 378 379 SelectedPilotLamp = SelectedListItem 380 .Select(x => x?.Tag.Value as PilotLampElement) 381 .Do(_ => SelectedPilotLamp?.Value?.Dispose()) 382 .Select(x => x != null ? new PilotLampElementViewModel(x) : null) 383 .ToReadOnlyReactivePropertySlim() 384 .AddTo(disposable); 385 386 SelectedNeedle = SelectedListItem 387 .Select(x => x?.Tag.Value as NeedleElement) 388 .Do(_ => SelectedNeedle?.Value?.Dispose()) 389 .Select(x => x != null ? new NeedleElementViewModel(x) : null) 390 .ToReadOnlyReactivePropertySlim() 391 .AddTo(disposable); 392 393 SelectedDigitalNumber = SelectedListItem 394 .Select(x => x?.Tag.Value as DigitalNumberElement) 395 .Do(_ => SelectedDigitalNumber?.Value?.Dispose()) 396 .Select(x => x != null ? new DigitalNumberElementViewModel(x) : null) 397 .ToReadOnlyReactivePropertySlim() 398 .AddTo(disposable); 399 400 SelectedDigitalGauge = SelectedListItem 401 .Select(x => x?.Tag.Value as DigitalGaugeElement) 402 .Do(_ => SelectedDigitalGauge?.Value?.Dispose()) 403 .Select(x => x != null ? new DigitalGaugeElementViewModel(x) : null) 404 .ToReadOnlyReactivePropertySlim() 405 .AddTo(disposable); 406 407 SelectedLinearGauge = SelectedListItem 408 .Select(x => x?.Tag.Value as LinearGaugeElement) 409 .Do(_ => SelectedLinearGauge?.Value?.Dispose()) 410 .Select(x => x != null ? new LinearGaugeElementViewModel(x) : null) 411 .ToReadOnlyReactivePropertySlim() 412 .AddTo(disposable); 413 414 SelectedTimetable = SelectedListItem 415 .Select(x => x?.Tag.Value as TimetableElement) 416 .Do(_ => SelectedTimetable?.Value?.Dispose()) 417 .Select(x => x != null ? new TimetableElementViewModel(x) : null) 418 .ToReadOnlyReactivePropertySlim() 419 .AddTo(disposable); 420 421 SelectedTouch = SelectedListItem 422 .Select(x => x?.Tag.Value as TouchElement) 423 .Do(_ => SelectedTouch?.Value?.Dispose()) 424 .Select(x => x != null ? new TouchElementViewModel(x) : null) 425 .ToReadOnlyReactivePropertySlim() 426 .AddTo(disposable); 427 428 AddScreen = SelectedTreeItem 429 .Select(x => x == TreeItem.Value.Children[1]) 430 .ToReactiveCommand() 431 .WithSubscribe(panel.AddScreen) 432 .AddTo(disposable); 433 434 AddPilotLamp = SelectedTreeItem 435 .Select(x => TreeItem.Value.Children[1].Children.Any(y => x == y.Children[0].Children[0]) 436 || x == TreeItem.Value.Children[2].Children[0]) 437 .ToReactiveCommand() 438 .WithSubscribe(panel.AddPilotLamp) 439 .AddTo(disposable); 440 441 AddNeedle = SelectedTreeItem 442 .Select(x => TreeItem.Value.Children[1].Children.Any(y => x == y.Children[0].Children[1]) 443 || x == TreeItem.Value.Children[2].Children[1]) 444 .ToReactiveCommand() 445 .WithSubscribe(panel.AddNeedle) 446 .AddTo(disposable); 447 448 AddDigitalNumber = SelectedTreeItem 449 .Select(x => TreeItem.Value.Children[1].Children.Any(y => x == y.Children[0].Children[2]) 450 || x == TreeItem.Value.Children[2].Children[2]) 451 .ToReactiveCommand() 452 .WithSubscribe(panel.AddDigitalNumber) 453 .AddTo(disposable); 454 455 AddDigitalGauge = SelectedTreeItem 456 .Select(x => TreeItem.Value.Children[1].Children.Any(y => x == y.Children[0].Children[3]) 457 || x == TreeItem.Value.Children[2].Children[3]) 458 .ToReactiveCommand() 459 .WithSubscribe(panel.AddDigitalGauge) 460 .AddTo(disposable); 461 462 AddLinearGauge = SelectedTreeItem 463 .Select(x => TreeItem.Value.Children[1].Children.Any(y => x == y.Children[0].Children[4]) 464 || x == TreeItem.Value.Children[2].Children[4]) 465 .ToReactiveCommand() 466 .WithSubscribe(panel.AddLinearGauge) 467 .AddTo(disposable); 468 469 AddTimetable = SelectedTreeItem 470 .Select(x => TreeItem.Value.Children[1].Children.Any(y => x == y.Children[0].Children[5]) 471 || x == TreeItem.Value.Children[2].Children[5]) 472 .ToReactiveCommand() 473 .WithSubscribe(panel.AddTimetable) 474 .AddTo(disposable); 475 476 AddTouch = SelectedTreeItem 477 .Select(x => TreeItem.Value.Children[1].Children.Any(y => x == y.Children[1])) 478 .ToReactiveCommand() 479 .WithSubscribe(panel.AddTouch) 480 .AddTo(disposable); 481 482 CopyScreen = SelectedScreen 483 .Select(x => x != null) 484 .ToReactiveCommand() 485 .WithSubscribe(panel.CopyScreen) 486 .AddTo(disposable); 487 488 CopyPilotLamp = SelectedPilotLamp 489 .Select(x => x != null) 490 .ToReactiveCommand() 491 .WithSubscribe(panel.CopyPilotLamp) 492 .AddTo(disposable); 493 494 CopyNeedle = SelectedNeedle 495 .Select(x => x != null) 496 .ToReactiveCommand() 497 .WithSubscribe(panel.CopyNeedle) 498 .AddTo(disposable); 499 500 CopyDigitalNumber = SelectedDigitalNumber 501 .Select(x => x != null) 502 .ToReactiveCommand() 503 .WithSubscribe(panel.CopyDigitalNumber) 504 .AddTo(disposable); 505 506 CopyDigitalGauge = SelectedDigitalGauge 507 .Select(x => x != null) 508 .ToReactiveCommand() 509 .WithSubscribe(panel.CopyDigitalGauge) 510 .AddTo(disposable); 511 512 CopyLinearGauge = SelectedLinearGauge 513 .Select(x => x != null) 514 .ToReactiveCommand() 515 .WithSubscribe(panel.CopyLinearGauge) 516 .AddTo(disposable); 517 518 CopyTimetable = SelectedTimetable 519 .Select(x => x != null) 520 .ToReactiveCommand() 521 .WithSubscribe(panel.CopyTimetable) 522 .AddTo(disposable); 523 524 CopyTouch = SelectedTouch 525 .Select(x => x != null) 526 .ToReactiveCommand() 527 .WithSubscribe(panel.CopyTouch) 528 .AddTo(disposable); 529 530 RemoveScreen = SelectedScreen 531 .Select(x => x != null) 532 .ToReactiveCommand() 533 .WithSubscribe(panel.RemoveScreen) 534 .AddTo(disposable); 535 536 RemovePilotLamp = SelectedPilotLamp 537 .Select(x => x != null) 538 .ToReactiveCommand() 539 .WithSubscribe(panel.RemovePilotLamp) 540 .AddTo(disposable); 541 542 RemoveNeedle = SelectedNeedle 543 .Select(x => x != null) 544 .ToReactiveCommand() 545 .WithSubscribe(panel.RemoveNeedle) 546 .AddTo(disposable); 547 548 RemoveDigitalNumber = SelectedDigitalNumber 549 .Select(x => x != null) 550 .ToReactiveCommand() 551 .WithSubscribe(panel.RemoveDigitalNumber) 552 .AddTo(disposable); 553 554 RemoveDigitalGauge = SelectedDigitalGauge 555 .Select(x => x != null) 556 .ToReactiveCommand() 557 .WithSubscribe(panel.RemoveDigitalGauge) 558 .AddTo(disposable); 559 560 RemoveLinearGauge = SelectedLinearGauge 561 .Select(x => x != null) 562 .ToReactiveCommand() 563 .WithSubscribe(panel.RemoveLinearGauge) 564 .AddTo(disposable); 565 566 RemoveTimetable = SelectedTimetable 567 .Select(x => x != null) 568 .ToReactiveCommand() 569 .WithSubscribe(panel.RemoveTimetable) 570 .AddTo(disposable); 571 572 RemoveTouch = SelectedTouch 573 .Select(x => x != null) 574 .ToReactiveCommand() 575 .WithSubscribe(panel.RemoveTouch) 576 .AddTo(disposable); 577 578 treeItemDisposable.AddTo(disposable); 579 listItemDisposable.AddTo(disposable); 580 } 581 } 582 } 583