[corlib] Avoid unnecessary ephemeron array resizes
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / VBIdentifierDesigner.xaml.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4
5 namespace System.Activities.Presentation.View
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Linq;
10     using System.Text;
11     using System.Windows;
12     using System.Windows.Controls;
13     using System.Windows.Data;
14     using System.Windows.Documents;
15     using System.Windows.Input;
16     using System.Windows.Media;
17     using System.Windows.Media.Imaging;
18     using System.Windows.Navigation;
19     using System.Windows.Shapes;
20     using System.Activities.Presentation.View;
21     using System.ComponentModel;
22     using System.Windows.Automation.Peers;
23     using System.Xml.Linq;
24     using System.Reflection;
25
26     partial class VBIdentifierDesigner : UserControl
27     {
28         public static readonly DependencyProperty IdentifierProperty =
29             DependencyProperty.Register("Identifier", typeof(VBIdentifierName), typeof(VBIdentifierDesigner), new UIPropertyMetadata(OnIdentifierChanged));
30
31         public static readonly DependencyProperty NameStringProperty =
32             DependencyProperty.Register("NameString", typeof(string), typeof(VBIdentifierDesigner), new UIPropertyMetadata(null, null, OnNameChanging));
33
34         public static readonly DependencyProperty IsReadOnlyProperty =
35             DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(VBIdentifierDesigner));
36
37         public event PropertyChangedEventHandler TextBoxPropertyChanged;
38
39         TextBox textBox;
40         bool isInternalChange;
41         bool checkAgainstXaml;
42
43         public VBIdentifierName Identifier
44         {
45             get { return (VBIdentifierName)GetValue(IdentifierProperty); }
46             set { SetValue(IdentifierProperty, value); }
47         }
48
49         public string NameString
50         {
51             get { return (string)GetValue(NameStringProperty); }
52             set { SetValue(NameStringProperty, value); }
53         }
54
55         public bool IsReadOnly
56         {
57             get { return (bool)GetValue(IsReadOnlyProperty); }
58             set { SetValue(IsReadOnlyProperty, value); }
59         }
60
61         internal TextBox IdentifierTextBox
62         {
63             get
64             {
65                 return this.textBox;
66             }
67             set
68             {
69                 if (value != this.textBox)
70                 {
71                     this.textBox = value;
72                     if (this.TextBoxPropertyChanged != null)
73                     {
74                         this.TextBoxPropertyChanged(this, new PropertyChangedEventArgs("IdentifierTextBox"));
75                     }
76                 }
77             }
78         }
79
80         public VBIdentifierDesigner()
81         {
82             InitializeComponent();
83             this.Loaded += (s, e) =>
84                 {
85                     //when designer gets loaded, get its identifier binding expression with parent control
86                     var binding = this.GetBindingExpression(VBIdentifierDesigner.IdentifierProperty);
87                     if (null != binding && null != binding.ParentBinding)
88                     {
89                         //if one exists - define update source exception filter
90                         binding.ParentBinding.UpdateSourceExceptionFilter = this.OnBindingException;
91                     }
92                 };
93         }
94
95
96         void OnTextBoxLoaded(object sender, RoutedEventArgs e)
97         {
98             this.IdentifierTextBox = sender as TextBox;
99             this.IdentifierTextBox.LostKeyboardFocus += this.OnTextBoxLostKeyboardFocus;
100         }
101
102         void OnTextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
103         {
104             if (this.IdentifierTextBox.IsFocused)
105             {
106                 DependencyObject focusScope = FocusManager.GetFocusScope(this.IdentifierTextBox);
107                 FocusManager.SetFocusedElement(focusScope, this);
108             }
109         }
110
111         void OnTextBoxUnloaded(object sender, RoutedEventArgs e)
112         {
113             TextBox textBox = sender as TextBox;
114             textBox.LostKeyboardFocus -= this.OnTextBoxLostKeyboardFocus;
115             this.IdentifierTextBox = null;
116         }
117
118         object OnBindingException(object sender, Exception err)
119         {
120             //whenever exception occurs, allow ValidationException to be rethrown - this exception is needed to revert invalid value
121             if (err is TargetInvocationException && err.InnerException is ValidationException || err is ValidationException)
122             {
123                 throw FxTrace.Exception.AsError( err.InnerException ?? err );
124             }
125             //simply return null - we don't use error template for this control
126             return null;
127         }
128
129         static object OnNameChanging(DependencyObject sender, object newValue)
130         {
131             var ctrl = (VBIdentifierDesigner)sender;
132             //before allowing new value to be assigned to property, check if it passes validation
133             return ctrl.OnNameChanging(ctrl.NameString, (string)newValue);
134         }
135
136         object OnNameChanging(string oldName, string newName)
137         {
138             string result = newName;
139             if (!this.isInternalChange)
140             {
141                 try
142                 {
143                     this.isInternalChange = true;
144                     //try to create new Identifier - if this call succeds, set the new value to a property
145                     this.Identifier = new VBIdentifierName(this.checkAgainstXaml) { IdentifierName = newName };
146                 }
147                 catch (ValidationException)
148                 {
149                     //in case of validation exception - do not allow new invalid value to be set
150                     result = oldName;
151                     //if text box is still visible - refresh its Text property to old value
152                     if (null != this.textBox)
153                     {
154                         var binding = this.textBox.GetBindingExpression(TextBox.TextProperty);
155                         binding.UpdateTarget();
156                     }
157                 }
158                 finally
159                 {
160                     this.isInternalChange = false;
161                 }
162             }
163             return result;
164         }
165
166         static void OnIdentifierChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
167         {
168             (sender as VBIdentifierDesigner).OnIdentifierChanged();
169         }
170
171         void OnIdentifierChanged()
172         {
173             if (!this.isInternalChange && null != this.Identifier)
174             {
175                 this.isInternalChange = true;
176                 this.NameString = this.Identifier.IdentifierName;
177                 this.isInternalChange = false;
178                 this.checkAgainstXaml = this.Identifier.CheckAgainstXaml;
179             }
180         }
181
182         protected override AutomationPeer OnCreateAutomationPeer()
183         {
184             return new VBIdentiferDesignerAutomationPeer(this);
185         }
186     }
187
188     class VBIdentiferDesignerAutomationPeer : UIElementAutomationPeer
189     {
190         public VBIdentiferDesignerAutomationPeer(VBIdentifierDesigner owner)
191             : base(owner)
192         {
193         }
194         
195         protected override string GetItemStatusCore()
196         {
197             VBIdentifierDesigner vbIdentifierDesigner = this.Owner as VBIdentifierDesigner;
198             if (vbIdentifierDesigner != null)
199             {
200                 VBIdentifierName vbIdentifier = vbIdentifierDesigner.Identifier;
201                 if (vbIdentifier != null)
202                 {
203                     XElement itemStatus = new XElement("VBIdentifierStatus",
204                         new XAttribute("Status", vbIdentifier.IsValid ? "Valid" : "Invalid"),
205                         new XAttribute("WarningMessage", vbIdentifier.ErrorMessage));
206                     return itemStatus.ToString();
207                 }
208             }
209             return base.GetItemStatusCore();
210         }
211     }
212 }