Exemple #1
0
		public Box(BoxViewModel viewModel, Caret caretPerTree)
		{
			this.DataContext = viewModel;

			this.CaretPerTree = caretPerTree;

			this.Focusable = true;
			this.Width = double.NaN;
			this.ShowGridLines = false;
			//this.SizeChanged += (sender, e) => { if (this.BoxParent != null) this.BoxParent.InvalidateMeasure(); throw new NotImplementedException("You'd think this is automated in WPF"); };

			this.viewModel.CaretPerTree.CaretChangedFocus += OnCaretChanged;
			OnCaretChanged(this.viewModel.Caret, new PropertyChangedEventArgs(nameof(BoxViewModel.Caret)));

			this.viewModel.Elements.CollectionChangedElementWise += OnElementsChanged;
			//trigger adding the initial elements. THe viewModel argument may already have some elements set
			if (viewModel.Elements.Count != 0)
			{
				var e = new NotifyBoxElementsChangedEventArgs(viewModel.Elements, NotifyCollectionChangedAction.Add, viewModel.Elements, 0);
				OnElementsChanged(viewModel.Elements, e);
			}

			this.viewModel.PropertyChanged += OnFocusableChanged;
			OnFocusableChanged(this.viewModel, new PropertyChangedEventArgs(nameof(BoxViewModel.Modifiable)));

			this.viewModel.Selections.CollectionChanged += OnSelectionsChanged;
			if (this.viewModel.Selections.Count != 0)
				OnSelectionsChanged(this.viewModel.Selections, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, this.viewModel.Selections, 0));
		}
		//Ok, so this is how this works.
		//we start with the root view model. It's treated like any other box in the view model. We hook into the box collection changed. when a box composition is added to some box, 
		//the event handler is triggered and registers a mutation associated with that box. A mutation is a lazy change, meaning that whenever that box is requested, the mutation takes place
		//This entails adding in the box composition to the name instance model and registering an eventhandler that handles subsequent changes to the box composition
		//(from the moment of implementation the mutation that adds it, not before) TODO: consider the case where the box composition was removed already

		//In case the box collection changed and added a glyph, again a mutation is added so that whenever the box is requested, the glyph gets added. 

		//The case for the box composition collection changed event handler is pretty symmetric. When a box is added, it registers a mutation with the box composition. 
		//whenever the box composition is requested, the mutation takes effect: it adds the box and hooks into its collection changed event.

		//removal works in the same manner, adding mutations that remove the boxes/box compositions and their respective handlers (and of all descendents as well). 
		private void onBoxElementsCollectionChanged(object boxElements, NotifyBoxElementsChangedEventArgs e)
		{
			var elements = (BoxElementsCollection)boxElements;

			switch (e.Action)
			{
				case NotifyCollectionChangedAction.Add:
					e.NewItems.VirtualForeach
					(
						(BoxCompositionViewModel newBoxComposition, int i) => this.AddNewBoxCompositionMutation(newBoxComposition, e.NewStartingIndex + i),
						(Glyph newGlyphRun, int i) => this.AddNewGlyphsMutation(newGlyphRun, e.NewStartingIndex + i, elements.Box)
					);
					break;
				case NotifyCollectionChangedAction.Remove:
					this.Without(elements.Box, e.OldStartingIndex, e.OldItems);
					break;
				case NotifyCollectionChangedAction.Reset:
					throw new ArgumentException("Use remove all, since otherwise I cannot access the removed elements");
				default:
					throw new NotImplementedException();
			}
		}