source: branches/GP.Grammar.Editor/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/SymbolicExpressionGrammarBase.cs @ 6415

Last change on this file since 6415 was 6415, checked in by mkommend, 8 years ago

#1479: Merged trunk changes, refactored grammar editor and added copy functionality.

File size: 22.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Collections;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
29
30namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
31  /// <summary>
32  /// The default symbolic expression grammar stores symbols and syntactic constraints for symbols.
33  /// Symbols are treated as equvivalent if they have the same name.
34  /// Syntactic constraints limit the number of allowed sub trees for a node with a symbol and which symbols are allowed
35  /// in the sub-trees of a symbol (can be specified for each sub-tree index separately).
36  /// </summary>
37  [StorableClass]
38  public abstract class SymbolicExpressionGrammarBase : NamedItem, ISymbolicExpressionGrammarBase {
39
40    #region properties for separation between implementation and persistence
41    [Storable(Name = "Symbols")]
42    private IEnumerable<ISymbol> StorableSymbols {
43      get { return symbols.Values.ToArray(); }
44      set { symbols = value.ToDictionary(sym => sym.Name); }
45    }
46
47    [Storable(Name = "SymbolSubtreeCount")]
48    private IEnumerable<KeyValuePair<ISymbol, Tuple<int, int>>> StorableSymbolSubtreeCount {
49      get { return symbolSubtreeCount.Select(x => new KeyValuePair<ISymbol, Tuple<int, int>>(GetSymbol(x.Key), x.Value)).ToArray(); }
50      set { symbolSubtreeCount = value.ToDictionary(x => x.Key.Name, x => x.Value); }
51    }
52
53    [Storable(Name = "AllowedChildSymbols")]
54    private IEnumerable<KeyValuePair<ISymbol, IEnumerable<ISymbol>>> StorableAllowedChildSymbols {
55      get { return allowedChildSymbols.Select(x => new KeyValuePair<ISymbol, IEnumerable<ISymbol>>(GetSymbol(x.Key), x.Value.Select(y => GetSymbol(y)).ToArray())).ToArray(); }
56      set { allowedChildSymbols = value.ToDictionary(x => x.Key.Name, x => x.Value.Select(y => y.Name).ToList()); }
57    }
58
59    [Storable(Name = "AllowedChildSymbolsPerIndex")]
60    private IEnumerable<KeyValuePair<Tuple<ISymbol, int>, IEnumerable<ISymbol>>> StorableAllowedChildSymbolsPerIndex {
61      get { return allowedChildSymbolsPerIndex.Select(x => new KeyValuePair<Tuple<ISymbol, int>, IEnumerable<ISymbol>>(Tuple.Create<ISymbol, int>(GetSymbol(x.Key.Item1), x.Key.Item2), x.Value.Select(y => GetSymbol(y)).ToArray())).ToArray(); }
62      set { allowedChildSymbolsPerIndex = value.ToDictionary(x => Tuple.Create(x.Key.Item1.Name, x.Key.Item2), x => x.Value.Select(y => y.Name).ToList()); }
63    }
64    #endregion
65
66    private bool suppressEvents;
67    protected Dictionary<string, ISymbol> symbols;
68    protected Dictionary<string, Tuple<int, int>> symbolSubtreeCount;
69    protected Dictionary<string, List<string>> allowedChildSymbols;
70    protected Dictionary<Tuple<string, int>, List<string>> allowedChildSymbolsPerIndex;
71
72    public override bool CanChangeName {
73      get { return false; }
74    }
75    public override bool CanChangeDescription {
76      get { return false; }
77    }
78
79    [StorableConstructor]
80    protected SymbolicExpressionGrammarBase(bool deserializing)
81      : base(deserializing) {
82      cachedMinExpressionLength = new Dictionary<string, int>();
83      cachedMaxExpressionLength = new Dictionary<string, int>();
84      cachedMinExpressionDepth = new Dictionary<string, int>();
85
86      suppressEvents = false;
87    }
88    [StorableHook(HookType.AfterDeserialization)]
89    private void AfterDeserialization() {
90      foreach (ISymbol symbol in symbols.Values)
91        RegisterSymbolEvents(symbol);
92    }
93
94    protected SymbolicExpressionGrammarBase(SymbolicExpressionGrammarBase original, Cloner cloner)
95      : base(original, cloner) {
96      cachedMinExpressionLength = new Dictionary<string, int>();
97      cachedMaxExpressionLength = new Dictionary<string, int>();
98      cachedMinExpressionDepth = new Dictionary<string, int>();
99
100      symbols = original.symbols.ToDictionary(x => x.Key, y => (ISymbol)cloner.Clone(y.Value));
101      symbolSubtreeCount = new Dictionary<string, Tuple<int, int>>(original.symbolSubtreeCount);
102
103      allowedChildSymbols = new Dictionary<string, List<string>>();
104      foreach (var element in original.allowedChildSymbols)
105        allowedChildSymbols.Add(element.Key, new List<string>(element.Value));
106
107      allowedChildSymbolsPerIndex = new Dictionary<Tuple<string, int>, List<string>>();
108      foreach (var element in original.allowedChildSymbolsPerIndex)
109        allowedChildSymbolsPerIndex.Add(element.Key, new List<string>(element.Value));
110
111      foreach (ISymbol symbol in symbols.Values)
112        RegisterSymbolEvents(symbol);
113
114      suppressEvents = false;
115    }
116
117    protected SymbolicExpressionGrammarBase(string name, string description)
118      : base(name, description) {
119      cachedMinExpressionLength = new Dictionary<string, int>();
120      cachedMaxExpressionLength = new Dictionary<string, int>();
121      cachedMinExpressionDepth = new Dictionary<string, int>();
122
123      symbols = new Dictionary<string, ISymbol>();
124      symbolSubtreeCount = new Dictionary<string, Tuple<int, int>>();
125      allowedChildSymbols = new Dictionary<string, List<string>>();
126      allowedChildSymbolsPerIndex = new Dictionary<Tuple<string, int>, List<string>>();
127
128      suppressEvents = false;
129    }
130
131    #region protected grammar manipulation methods
132    protected void AddSymbol(ISymbol symbol) {
133      foreach (ISymbol s in symbol.Flatten())
134        AddSymbolToDictionaries(s);
135
136      ClearCaches();
137      OnChanged();
138    }
139    private void AddSymbolToDictionaries(ISymbol symbol) {
140      symbols.Add(symbol.Name, symbol);
141      symbolSubtreeCount.Add(symbol.Name, Tuple.Create(symbol.MinimumArity, symbol.MinimumArity));
142      RegisterSymbolEvents(symbol);
143    }
144
145    protected void RemoveSymbol(ISymbol symbol) {
146      foreach (ISymbol s in symbol.Flatten())
147        RemoveSymbolFromDictionaries(s);
148
149      foreach (GroupSymbol group in symbols.Values.OfType<GroupSymbol>())
150        group.SymbolsCollection.Remove(symbol);
151
152      ClearCaches();
153      OnChanged();
154    }
155    private void RemoveSymbolFromDictionaries(ISymbol symbol) {
156      symbols.Remove(symbol.Name);
157      allowedChildSymbols.Remove(symbol.Name);
158      for (int i = 0; i < GetMaximumSubtreeCount(symbol); i++)
159        allowedChildSymbolsPerIndex.Remove(Tuple.Create(symbol.Name, i));
160      symbolSubtreeCount.Remove(symbol.Name);
161
162      foreach (var parent in Symbols) {
163        List<string> allowedChilds;
164        if (allowedChildSymbols.TryGetValue(parent.Name, out allowedChilds))
165          allowedChilds.Remove(symbol.Name);
166
167        for (int i = 0; i < GetMaximumSubtreeCount(parent); i++) {
168          if (allowedChildSymbolsPerIndex.TryGetValue(Tuple.Create(parent.Name, i), out allowedChilds))
169            allowedChilds.Remove(symbol.Name);
170        }
171      }
172      DeregisterSymbolEvents(symbol);
173    }
174
175    public virtual ISymbol GetSymbol(string symbolName) {
176      ISymbol symbol;
177      if (symbols.TryGetValue(symbolName, out symbol)) return symbol;
178      return null;
179    }
180
181    protected void AddAllowedChildSymbol(ISymbol parent, ISymbol child) {
182      bool changed = false;
183
184      foreach (ISymbol p in parent.Flatten().Where(p => !(p is GroupSymbol)))
185        changed |= AddAllowedChildSymbolToDictionaries(p, child);
186
187      if (changed) {
188        ClearCaches();
189        OnChanged();
190      }
191    }
192
193    private bool AddAllowedChildSymbolToDictionaries(ISymbol parent, ISymbol child) {
194      List<string> childSymbols;
195      if (!allowedChildSymbols.TryGetValue(parent.Name, out childSymbols)) {
196        childSymbols = new List<string>();
197        allowedChildSymbols.Add(parent.Name, childSymbols);
198      }
199      if (childSymbols.Contains(child.Name)) return false;
200
201      suppressEvents = true;
202      for (int argumentIndex = 0; argumentIndex < GetMaximumSubtreeCount(parent); argumentIndex++)
203        RemoveAllowedChildSymbol(parent, child, argumentIndex);
204      suppressEvents = false;
205
206      childSymbols.Add(child.Name);
207      return true;
208    }
209
210    protected void AddAllowedChildSymbol(ISymbol parent, ISymbol child, int argumentIndex) {
211      bool changed = false;
212
213      foreach (ISymbol p in parent.Flatten().Where(p => !(p is GroupSymbol)))
214        changed |= AddAllowedChildSymbolToDictionaries(p, child, argumentIndex);
215
216      if (changed) {
217        ClearCaches();
218        OnChanged();
219      }
220    }
221
222
223    private bool AddAllowedChildSymbolToDictionaries(ISymbol parent, ISymbol child, int argumentIndex) {
224      List<string> childSymbols;
225      if (!allowedChildSymbols.TryGetValue(parent.Name, out childSymbols)) {
226        childSymbols = new List<string>();
227        allowedChildSymbols.Add(parent.Name, childSymbols);
228      }
229      if (childSymbols.Contains(child.Name)) return false;
230
231
232      var key = Tuple.Create(parent.Name, argumentIndex);
233      if (!allowedChildSymbolsPerIndex.TryGetValue(key, out childSymbols)) {
234        childSymbols = new List<string>();
235        allowedChildSymbolsPerIndex.Add(key, childSymbols);
236      }
237
238      if (childSymbols.Contains(child.Name)) return false;
239
240      childSymbols.Add(child.Name);
241      return true;
242    }
243
244    protected void RemoveAllowedChildSymbol(ISymbol parent, ISymbol child) {
245      bool changed = false;
246      List<string> childSymbols;
247      if (allowedChildSymbols.TryGetValue(child.Name, out childSymbols)) {
248        changed |= childSymbols.Remove(child.Name);
249      }
250
251      for (int argumentIndex = 0; argumentIndex < GetMaximumSubtreeCount(parent); argumentIndex++) {
252        var key = Tuple.Create(parent.Name, argumentIndex);
253        if (allowedChildSymbolsPerIndex.TryGetValue(key, out childSymbols))
254          changed |= childSymbols.Remove(child.Name);
255      }
256
257      if (changed) {
258        ClearCaches();
259        OnChanged();
260      }
261    }
262
263    protected void RemoveAllowedChildSymbol(ISymbol parent, ISymbol child, int argumentIndex) {
264      bool changed = false;
265
266      suppressEvents = true;
267      List<string> childSymbols;
268      if (allowedChildSymbols.TryGetValue(parent.Name, out childSymbols)) {
269        if (childSymbols.Remove(child.Name)) {
270          for (int i = 0; i < GetMaximumSubtreeCount(parent); i++) {
271            if (i != argumentIndex) AddAllowedChildSymbol(parent, child, i);
272          }
273          changed = true;
274        }
275      }
276      suppressEvents = false;
277
278      var key = Tuple.Create(parent.Name, argumentIndex);
279      if (allowedChildSymbolsPerIndex.TryGetValue(key, out childSymbols))
280        changed |= childSymbols.Remove(child.Name);
281
282      if (changed) {
283        ClearCaches();
284        OnChanged();
285      }
286    }
287
288    protected void SetSubtreeCount(ISymbol symbol, int minimumSubtreeCount, int maximumSubtreeCount) {
289      var symbols = symbol.Flatten().Where(s => !(s is GroupSymbol));
290      if (symbols.Any(s => s.MinimumArity > minimumSubtreeCount)) throw new ArgumentException("Invalid minimum subtree count " + minimumSubtreeCount + " for " + symbol);
291      if (symbols.Any(s => s.MaximumArity < maximumSubtreeCount)) throw new ArgumentException("Invalid minimum subtree count " + minimumSubtreeCount + " for " + symbol);
292
293      foreach (ISymbol s in symbols)
294        SetSubTreeCountInDictionaries(s, minimumSubtreeCount, maximumSubtreeCount);
295
296      ClearCaches();
297      OnChanged();
298    }
299
300    private void SetSubTreeCountInDictionaries(ISymbol symbol, int minimumSubtreeCount, int maximumSubtreeCount) {
301      for (int i = maximumSubtreeCount; i < GetMaximumSubtreeCount(symbol); i++) {
302        var key = Tuple.Create(symbol.Name, i);
303        allowedChildSymbolsPerIndex.Remove(key);
304      }
305
306      symbolSubtreeCount[symbol.Name] = Tuple.Create(minimumSubtreeCount, maximumSubtreeCount);
307    }
308    #endregion
309
310    public virtual IEnumerable<ISymbol> Symbols {
311      get { return symbols.Values; }
312    }
313    public virtual IEnumerable<ISymbol> AllowedSymbols {
314      get { return Symbols.Where(s => s.Enabled); }
315    }
316    public virtual bool ContainsSymbol(ISymbol symbol) {
317      return symbols.ContainsKey(symbol.Name);
318    }
319
320    public virtual bool IsAllowedChildSymbol(ISymbol parent, ISymbol child) {
321      if (!child.Enabled) return false;
322
323      List<string> temp;
324      if (allowedChildSymbols.TryGetValue(parent.Name, out temp)) {
325        if (temp.Contains(child.Name)) return true;
326        if (temp.SelectMany(s => GetSymbol(s).Flatten().Select(n => n.Name)).Contains(child.Name)) return true;
327      }
328      return false;
329    }
330
331    public virtual bool IsAllowedChildSymbol(ISymbol parent, ISymbol child, int argumentIndex) {
332      if (!child.Enabled) return false;
333      if (IsAllowedChildSymbol(parent, child)) return true;
334
335      List<string> temp;
336      var key = Tuple.Create(parent.Name, argumentIndex);
337      if (allowedChildSymbolsPerIndex.TryGetValue(key, out temp)) {
338        if (temp.Contains(child.Name)) return true;
339        if (temp.SelectMany(s => GetSymbol(s).Flatten().Select(n => n.Name)).Contains(child.Name)) return true;
340      }
341      return false;
342    }
343
344    public virtual IEnumerable<ISymbol> GetAllowedChildSymbols(ISymbol parent) {
345      List<string> childs;
346      if (!allowedChildSymbols.TryGetValue(parent.Name, out childs))
347        return Enumerable.Empty<ISymbol>();
348
349      return childs.Select(x => GetSymbol(x)).Where(s => s.Enabled);
350    }
351
352    public virtual IEnumerable<ISymbol> GetAllowedChildSymbols(ISymbol parent, int argumentIndex) {
353      var result = Enumerable.Empty<string>();
354
355      List<string> temp;
356      if (allowedChildSymbols.TryGetValue(parent.Name, out temp))
357        result = result.Union(temp);
358      var key = Tuple.Create(parent.Name, argumentIndex);
359      if (allowedChildSymbolsPerIndex.TryGetValue(key, out temp))
360        result = result.Union(temp);
361
362      return result.Select(x => GetSymbol(x)).Where(s => s.Enabled);
363    }
364
365    public virtual int GetMinimumSubtreeCount(ISymbol symbol) {
366      return symbolSubtreeCount[symbol.Name].Item1;
367    }
368    public virtual int GetMaximumSubtreeCount(ISymbol symbol) {
369      return symbolSubtreeCount[symbol.Name].Item2;
370    }
371
372    private void ClearCaches() {
373      cachedMinExpressionLength.Clear();
374      cachedMaxExpressionLength.Clear();
375      cachedMinExpressionDepth.Clear();
376    }
377
378    private Dictionary<string, int> cachedMinExpressionLength;
379    public int GetMinimumExpressionLength(ISymbol symbol) {
380      int temp;
381      if (!cachedMinExpressionLength.TryGetValue(symbol.Name, out temp)) {
382        cachedMinExpressionLength[symbol.Name] = int.MaxValue; // prevent infinite recursion
383        long sumOfMinExpressionLengths = 1 + (from argIndex in Enumerable.Range(0, GetMinimumSubtreeCount(symbol))
384                                              let minForSlot = (long)(from s in GetAllowedChildSymbols(symbol, argIndex)
385                                                                      select GetMinimumExpressionLength(s)).DefaultIfEmpty(0).Min()
386                                              select minForSlot).DefaultIfEmpty(0).Sum();
387
388        cachedMinExpressionLength[symbol.Name] = (int)Math.Min(sumOfMinExpressionLengths, int.MaxValue);
389        return cachedMinExpressionLength[symbol.Name];
390      }
391      return temp;
392    }
393
394    private Dictionary<string, int> cachedMaxExpressionLength;
395    public int GetMaximumExpressionLength(ISymbol symbol) {
396      int temp;
397      if (!cachedMaxExpressionLength.TryGetValue(symbol.Name, out temp)) {
398        cachedMaxExpressionLength[symbol.Name] = int.MaxValue; // prevent infinite recursion
399        long sumOfMaxTrees = 1 + (from argIndex in Enumerable.Range(0, GetMaximumSubtreeCount(symbol))
400                                  let maxForSlot = (long)(from s in GetAllowedChildSymbols(symbol, argIndex)
401                                                          select GetMaximumExpressionLength(s)).DefaultIfEmpty(0).Max()
402                                  select maxForSlot).DefaultIfEmpty(0).Sum();
403        cachedMaxExpressionLength[symbol.Name] = (int)Math.Min(sumOfMaxTrees, int.MaxValue);
404        return cachedMaxExpressionLength[symbol.Name];
405      }
406      return temp;
407    }
408
409    private Dictionary<string, int> cachedMinExpressionDepth;
410    public int GetMinimumExpressionDepth(ISymbol symbol) {
411      int temp;
412      if (!cachedMinExpressionDepth.TryGetValue(symbol.Name, out temp)) {
413        cachedMinExpressionDepth[symbol.Name] = int.MaxValue; // prevent infinite recursion
414        long minDepth = 1 + (from argIndex in Enumerable.Range(0, GetMinimumSubtreeCount(symbol))
415                             let minForSlot = (long)(from s in GetAllowedChildSymbols(symbol, argIndex)
416                                                     select GetMinimumExpressionDepth(s)).DefaultIfEmpty(0).Min()
417                             select minForSlot).DefaultIfEmpty(0).Max();
418        cachedMinExpressionDepth[symbol.Name] = (int)Math.Min(minDepth, int.MaxValue);
419        return cachedMinExpressionDepth[symbol.Name];
420      }
421      return temp;
422    }
423
424    #region events
425    private void RegisterSymbolEvents(ISymbol symbol) {
426      symbol.NameChanging += new EventHandler<CancelEventArgs<string>>(Symbol_NameChanging);
427      symbol.NameChanged += new EventHandler(Symbol_NameChanged);
428      symbol.Changed += new EventHandler(Symbol_Changed);
429      var groupSymbol = symbol as GroupSymbol;
430      if (groupSymbol != null) RegisterGroupSymbolEvents(groupSymbol);
431    }
432    private void DeregisterSymbolEvents(ISymbol symbol) {
433      symbol.NameChanging -= new EventHandler<CancelEventArgs<string>>(Symbol_NameChanging);
434      symbol.NameChanged -= new EventHandler(Symbol_NameChanged);
435      symbol.Changed -= new EventHandler(Symbol_Changed);
436      var groupSymbol = symbol as GroupSymbol;
437      if (groupSymbol != null) DeregisterGroupSymbolEvents(groupSymbol);
438    }
439
440    private void RegisterGroupSymbolEvents(GroupSymbol groupSymbol) {
441      groupSymbol.SymbolsCollection.ItemsAdded += new Collections.CollectionItemsChangedEventHandler<ISymbol>(GroupSymbol_ItemsAdded);
442      groupSymbol.SymbolsCollection.ItemsRemoved += new Collections.CollectionItemsChangedEventHandler<ISymbol>(GroupSymbol_ItemsRemoved);
443      groupSymbol.SymbolsCollection.CollectionReset += new Collections.CollectionItemsChangedEventHandler<ISymbol>(GroupSymbol_CollectionReset);
444    }
445    private void DeregisterGroupSymbolEvents(GroupSymbol groupSymbol) {
446      groupSymbol.SymbolsCollection.ItemsAdded -= new Collections.CollectionItemsChangedEventHandler<ISymbol>(GroupSymbol_ItemsAdded);
447      groupSymbol.SymbolsCollection.ItemsRemoved -= new Collections.CollectionItemsChangedEventHandler<ISymbol>(GroupSymbol_ItemsRemoved);
448      groupSymbol.SymbolsCollection.CollectionReset -= new Collections.CollectionItemsChangedEventHandler<ISymbol>(GroupSymbol_CollectionReset);
449    }
450
451    private void Symbol_NameChanging(object sender, CancelEventArgs<string> e) {
452      if (symbols.ContainsKey(e.Value)) e.Cancel = true;
453    }
454    private void Symbol_NameChanged(object sender, EventArgs e) {
455      ISymbol symbol = (ISymbol)sender;
456      string oldName = symbols.Where(x => x.Value == symbol).First().Key;
457      string newName = symbol.Name;
458
459      symbols.Remove(oldName);
460      symbols.Add(newName, symbol);
461
462      var subtreeCount = symbolSubtreeCount[oldName];
463      symbolSubtreeCount.Remove(oldName);
464      symbolSubtreeCount.Add(newName, subtreeCount);
465
466      List<string> allowedChilds;
467      if (allowedChildSymbols.TryGetValue(oldName, out allowedChilds)) {
468        allowedChildSymbols.Remove(oldName);
469        allowedChildSymbols.Add(newName, allowedChilds);
470      }
471
472      for (int i = 0; i < GetMaximumSubtreeCount(symbol); i++) {
473        if (allowedChildSymbolsPerIndex.TryGetValue(Tuple.Create(oldName, i), out allowedChilds)) {
474          allowedChildSymbolsPerIndex.Remove(Tuple.Create(oldName, i));
475          allowedChildSymbolsPerIndex.Add(Tuple.Create(newName, i), allowedChilds);
476        }
477      }
478
479      foreach (var parent in Symbols) {
480        if (allowedChildSymbols.TryGetValue(parent.Name, out allowedChilds))
481          if (allowedChilds.Remove(oldName))
482            allowedChilds.Add(newName);
483
484        for (int i = 0; i < GetMaximumSubtreeCount(parent); i++) {
485          if (allowedChildSymbolsPerIndex.TryGetValue(Tuple.Create(parent.Name, i), out allowedChilds))
486            if (allowedChilds.Remove(oldName)) allowedChilds.Add(newName);
487        }
488      }
489
490      ClearCaches();
491      OnChanged();
492    }
493
494    private void Symbol_Changed(object sende, EventArgs e) {
495      ClearCaches();
496      OnChanged();
497    }
498
499    private void GroupSymbol_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ISymbol> e) {
500      suppressEvents = true;
501      foreach (ISymbol symbol in e.Items)
502        if (!ContainsSymbol(symbol))
503          AddSymbol(symbol);
504      suppressEvents = false;
505      OnChanged();
506    }
507    private void GroupSymbol_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ISymbol> e) {
508      suppressEvents = true;
509      foreach (ISymbol symbol in e.Items)
510        if (ContainsSymbol(symbol))
511          RemoveSymbol(symbol);
512      suppressEvents = false;
513      OnChanged();
514    }
515    private void GroupSymbol_CollectionReset(object sender, CollectionItemsChangedEventArgs<ISymbol> e) {
516      suppressEvents = true;
517      foreach (ISymbol symbol in e.Items)
518        if (!ContainsSymbol(symbol))
519          AddSymbol(symbol);
520      foreach (ISymbol symbol in e.OldItems)
521        if (ContainsSymbol(symbol))
522          RemoveSymbol(symbol);
523      suppressEvents = false;
524      OnChanged();
525    }
526
527    public event EventHandler Changed;
528    protected virtual void OnChanged() {
529      if (suppressEvents) return;
530      var handler = Changed;
531      if (handler != null) Changed(this, EventArgs.Empty);
532    }
533    #endregion
534  }
535}
Note: See TracBrowser for help on using the repository browser.