source: trunk/CrypPlugins/WorkspaceManager/View/VisualComponents/TaskPaneCtrl.xaml.cs @ 2072

Last change on this file since 2072 was 2072, checked in by matkovic, 11 years ago

-Slight style changes
-settings now is now ~80% working
-tooltip added

File size: 57.1 KB
Line 
1/*
2   Copyright 2008 Martin Saternus, Arno Wacker, Thomas Schmid, Sebastian Przybylski
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16using System.Collections.Generic;
17using System.Reflection;
18using System.Windows;
19using System.Windows.Controls;
20using System.Windows.Data;
21using System.Windows.Documents;
22using System.Windows.Input;
23using System.Windows.Media;
24using System.Windows.Shapes;
25using Cryptool.PluginBase;
26using Cryptool.PluginBase.Validation;
27using Microsoft.Win32;
28using System.Diagnostics;
29using System.Windows.Navigation;
30using System.Collections.ObjectModel;
31using System;
32using Cryptool.PluginBase.Miscellaneous;
33using System.Windows.Controls.Primitives;
34using Cryptool.PluginBase.Editor;
35using System.ComponentModel;
36using System.Windows.Threading;
37using System.Threading;
38using System.Text.RegularExpressions;
39
40namespace WorkspaceManager.View.VisualComponents
41{
42    public partial class TaskPaneCtrl : UserControl
43    {
44        private const int CONTROL_OFFSET = 10;
45        private const int SETTINGS_FORMAT_INDENT_OFFSET = 15;
46        private const int EXPANDER_GROUP_LEFT_RIGHT_OFFSET = 5;
47        private readonly Thickness CONTROL_DEFAULT_MARGIN = new Thickness(4, 0, 0, 0);
48        private Dictionary<IPlugin, List<UIElement>> dicPluginSettings = new Dictionary<IPlugin, List<UIElement>>();
49        private Dictionary<IPlugin, List<UIElement>> dicPluginSettingsToDisable = new Dictionary<IPlugin, List<UIElement>>();
50        private Dictionary<ISettings, Dictionary<string, TaskPaneSettingsForPlugins>> dicAllPluginSettings = new Dictionary<ISettings, Dictionary<string, TaskPaneSettingsForPlugins>>();
51        // private List<TaskPaneSettingsForPlugins> listAllPluginSettings = new List<TaskPaneSettingsForPlugins>();
52        private List<IPlugin> listAlwaysDisabled = new List<IPlugin>();
53        private IPlugin activePlugin;
54        private Dictionary<ISettings, Dictionary<string, List<RadioButton>>> dicRadioButtons = new Dictionary<ISettings, Dictionary<string, List<RadioButton>>>();
55
56        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
57
58        public TaskPaneCtrl()
59        {
60            InitializeComponent();
61            this.Loaded += TaskPaneCtrl_Loaded;
62            this.Height = double.NaN;
63            this.Width = double.NaN;
64        }
65
66        void TaskPaneCtrl_Loaded(object sender, RoutedEventArgs e)
67        {
68            // Hide the native expand button of naviPane, because we use resize/hide functions of SplitPanel Element
69            //Button naviPaneExpandButton = navPaneSettings.Template.FindName("ExpandButton", navPaneSettings) as Button;
70            //if (naviPaneExpandButton != null) naviPaneExpandButton.Visibility = Visibility.Collapsed;
71        }
72
73        public void ClearCache()
74        {
75            dicPluginSettings.Clear();
76            dicPluginSettingsToDisable.Clear();
77
78            // mwander 20100224
79            dicAllPluginSettings.Clear();
80            listAlwaysDisabled.Clear();
81            dicRadioButtons.Clear();
82            ClearCurrentChildren();
83        }
84
85        private void ClearCurrentChildren()
86        {
87            //stackPanelContent.Children.Clear();
88        }
89
90        private bool isChangeable = true;
91        public bool IsChangeable
92        {
93            get { return isChangeable; }
94            set
95            {
96                isChangeable = value;
97                if (activePlugin != null) SetPluginEnabled(activePlugin, isChangeable);
98            }
99        }
100
101        public void SetPluginEnabled(IPlugin plugin, bool isEnabled)
102        {
103            try
104            {
105                if (dicPluginSettingsToDisable.ContainsKey(plugin))
106                {
107                    foreach (UIElement ui in dicPluginSettingsToDisable[plugin])
108                    {
109                        ui.IsEnabled = isEnabled && !listAlwaysDisabled.Contains(plugin);
110                    }
111                    this.isChangeable = isEnabled;
112                }
113            }
114            catch (Exception exception)
115            {
116                GuiLogMessage(exception.Message, NotificationLevel.Error);
117            }
118        }
119
120        public void DisplayPluginSettings(IPlugin plugin, string title, DisplayPluginMode mode)
121        {
122            try
123            {
124                ClearCurrentChildren();
125                activePlugin = plugin;
126
127                if (plugin != null)
128                {
129                    if (title == null) title = string.Empty;
130
131                    ISettings settings = plugin.Settings;
132                    if (settings != null && !dicPluginSettings.ContainsKey(plugin))
133                    {
134                        if (mode == DisplayPluginMode.Disabled && !listAlwaysDisabled.Contains(plugin))
135                            listAlwaysDisabled.Add(plugin);
136
137                        List<BindingInfo> bindingList = new List<BindingInfo>();
138                        foreach (TaskPaneAttribute tpa in settings.GetSettingsProperties(plugin))
139                        {
140                            BindingInfo bInfo = null;
141                            bInfo = new BindingInfo(tpa);
142                            bindingList.Add(bInfo);
143                            bInfo.Settings = settings;
144                            if (bInfo != null && settings.GetSettingsFormat(bInfo.TaskPaneSettingsAttribute.PropertyName) != null)
145                                bInfo.SettingFormat = settings.GetSettingsFormat(bInfo.TaskPaneSettingsAttribute.PropertyName);
146                        }
147                        bindingList.Sort(new BindingInfoComparer());
148                        AddOutputControls(bindingList, settings, plugin, title);
149
150                        // save elements to list, on next display request they won't be recreated and the old group-expand-state still exists             
151                        List<UIElement> list = new List<UIElement>();
152                        foreach (UIElement uIElement in stackPanelContent.Children)
153                        {
154                            list.Add(uIElement);
155                        }
156                        dicPluginSettings.Add(plugin, list);
157                    }
158                    else if (dicPluginSettings.ContainsKey(plugin))
159                    {
160                        ClearCurrentChildren();
161                        foreach (UIElement ui in dicPluginSettings[plugin])
162                        {
163                            // baseStackPanel.Children.Add(ui);
164                            stackPanelContent.Children.Add(ui);
165                        }
166                    }
167                    this.SetPluginEnabled(plugin, isChangeable);
168                }
169            }
170            catch (Exception exception)
171            {
172                GuiLogMessage(exception.Message, NotificationLevel.Error);
173            }
174        }
175
176
177
178        /// <summary>
179        /// All the GUI elements used to display the options are created here.
180        /// </summary>
181        /// <param name="bindingList">The binding list.</param>
182        /// <param name="settings">The settings.</param>
183        /// <param name="plugin">The plugin.</param>
184        /// <param name="title">The title.</param>
185        private void AddOutputControls(List<BindingInfo> bindingList, ISettings settings, IPlugin plugin, string title)
186        {
187            try
188            {
189                ClearCurrentChildren();
190
191                string emptyGroup = Guid.NewGuid().ToString();
192                Dictionary<string, List<UIElement>> dicGroupedElements = new Dictionary<string, List<UIElement>>();
193                dicGroupedElements.Add(emptyGroup, new List<UIElement>());
194                Dictionary<string, List<KeyValuePair<BindingInfo, UIElement>>> dicVerticalSubGroups = new Dictionary<string, List<KeyValuePair<BindingInfo, UIElement>>>();
195                bool taskPaneAttributesCanChange = plugin.Settings.GetTaskPaneAttributeChanged() != null;
196                foreach (BindingInfo bInfo in bindingList)
197                {
198                    Binding dataBinding = new Binding(bInfo.TaskPaneSettingsAttribute.PropertyName);
199                    dataBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
200                    dataBinding.Mode = BindingMode.TwoWay;
201                    dataBinding.Source = settings;
202
203                    UIElement inputControl = null;
204
205                    switch (bInfo.TaskPaneSettingsAttribute.ControlType)
206                    {
207                        # region TextBox
208                        case ControlType.TextBox:
209                            TextBox textbox = new TextBox();
210                            textbox.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
211                            textbox.MouseEnter += Control_MouseEnter;
212                            if (
213                                bInfo.TaskPaneSettingsAttribute.RegularExpression != null &&
214                                bInfo.TaskPaneSettingsAttribute.RegularExpression != string.Empty)
215                            {
216                                ControlTemplate validationTemplate = Application.Current.Resources["validationTemplate"] as ControlTemplate;
217                                Style tbStyle = Application.Current.Resources["textStyleTextBox"] as Style;
218                                textbox.Style = tbStyle;
219                                RegExRule regExRule = new RegExRule();
220                                regExRule.RegExValue = bInfo.TaskPaneSettingsAttribute.RegularExpression;
221                                Validation.SetErrorTemplate(textbox, validationTemplate);
222                                dataBinding.ValidationRules.Add(regExRule);
223                                dataBinding.NotifyOnValidationError = true;
224                            }
225                            // this flag is set to true here, because only then the OnPropertyChanged events in
226                            // the property setter will result in an GUI update of this textBox.
227                            // TODO: add IMultiValueConverter option to TaskPane settings.
228                            // dataBinding.IsAsync = true;                                     
229                            textbox.SetBinding(TextBox.TextProperty, dataBinding);
230                            inputControl = textbox;
231                            break;
232                        # endregion TextBox
233                        # region NumericUpDown
234                        case ControlType.NumericUpDown:
235                            if (bInfo.TaskPaneSettingsAttribute.ValidationType == ValidationType.RangeInteger)
236                            {
237                                TextBlock intInput = new TextBlock();
238                                intInput.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
239                                intInput.MouseEnter += Control_MouseEnter;
240                                //intInput.MaxValue = bInfo.TaskPaneSettingsAttribute.IntegerMaxValue;
241                                //intInput.MinValue = bInfo.TaskPaneSettingsAttribute.IntegerMinValue;
242                                intInput.SetBinding(TextBlock.TextProperty, dataBinding);
243                                inputControl = intInput;
244                                bInfo.CaptionGUIElement = intInput;
245                            }
246                            else if (bInfo.TaskPaneSettingsAttribute.ValidationType == ValidationType.RangeDouble)
247                            {
248                                TextBlock doubleInput = new TextBlock();
249                                doubleInput.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
250                                doubleInput.MouseEnter += Control_MouseEnter;
251                                //doubleInput.MaxValue = bInfo.TaskPaneSettingsAttribute.DoubleMaxValue;
252                                //doubleInput.MinValue = bInfo.TaskPaneSettingsAttribute.DoubleMaxValue;
253                                doubleInput.SetBinding(TextBlock.TextProperty, dataBinding);
254                                inputControl = doubleInput;
255                                bInfo.CaptionGUIElement = doubleInput;
256                            }
257                            break;
258                        # endregion NumericUpDown
259                        # region ComboBox
260                        case ControlType.ComboBox:
261                            ComboBox comboBox = new ComboBox();
262                            comboBox.Margin = new Thickness(0);
263                            comboBox.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
264                            comboBox.MouseEnter += Control_MouseEnter;
265
266                            object value = bInfo.Settings.GetType().GetProperty(bInfo.TaskPaneSettingsAttribute.PropertyName).GetValue(bInfo.Settings, null);
267                            bool isEnum = value is Enum;
268
269                            if (isEnum) // use generic enum<->int converter
270                                dataBinding.Converter = EnumToIntConverter.GetInstance();
271
272                            if (bInfo.TaskPaneSettingsAttribute.ControlValues != null) // show manually passed entries in ComboBox
273                                comboBox.ItemsSource = bInfo.TaskPaneSettingsAttribute.ControlValues;
274                            else if (isEnum) // show automatically derived enum entries in ComboBox
275                                comboBox.ItemsSource = Enum.GetValues(value.GetType());
276                            else // nothing to show
277                                GuiLogMessage("No ComboBox entries given", NotificationLevel.Error);
278
279                            comboBox.SetBinding(ComboBox.SelectedIndexProperty, dataBinding);
280                            inputControl = comboBox;
281                            bInfo.CaptionGUIElement = comboBox;
282                            break;
283                        # endregion ComboBox
284                        # region RadioButton
285                        case ControlType.RadioButton:
286                            try
287                            {
288                                bInfo.Settings.PropertyChanged += RadioButton_PropertyChanged;
289                                if (!dicRadioButtons.ContainsKey(bInfo.Settings))
290                                {
291                                    dicRadioButtons.Add(bInfo.Settings, new Dictionary<string, List<RadioButton>>());
292                                }
293                                List<RadioButton> list = new List<RadioButton>();
294                                StackPanel panelRadioButtons = new StackPanel();
295                                panelRadioButtons.ToolTip = bInfo.TaskPaneSettingsAttribute.ToolTip;
296                                panelRadioButtons.MouseEnter += Control_MouseEnter;
297                                panelRadioButtons.Margin = CONTROL_DEFAULT_MARGIN;
298
299                                int selectedRadioButton = (int)bInfo.Settings.GetType().GetProperty(bInfo.TaskPaneSettingsAttribute.PropertyName).GetValue(bInfo.Settings, null);
300                                string groupNameExtension = Guid.NewGuid().ToString();
301                                foreach (string stringValue in bInfo.TaskPaneSettingsAttribute.ControlValues)
302                                {
303                                    RadioButton radio = new RadioButton();
304                                    radio.GroupName = bInfo.TaskPaneSettingsAttribute.PropertyName + groupNameExtension;
305                                    radio.Content = stringValue;
306                                    if (panelRadioButtons.Children.Count == selectedRadioButton)
307                                    {
308                                        radio.IsChecked = true;
309                                    }
310                                    radio.Tag = new RadioButtonListAndBindingInfo(list, bInfo);
311                                    radio.Checked += RadioButton_Checked;
312                                    panelRadioButtons.Children.Add(radio);
313                                    list.Add(radio);
314                                }
315                                dicRadioButtons[bInfo.Settings].Add(bInfo.TaskPaneSettingsAttribute.PropertyName, list);
316                                inputControl = panelRadioButtons;
317                                bInfo.CaptionGUIElement = panelRadioButtons;
318                            }
319                            catch (Exception ex)
320                            {
321                                GuiLogMessage(ex.Message, NotificationLevel.Error);
322                            }
323                            break;
324                        #endregion RadioButton
325                        # region DynamicComboBox
326                        case ControlType.DynamicComboBox:
327                            PropertyInfo pInfo = settings.GetType().GetProperty(bInfo.TaskPaneSettingsAttribute.ControlValues[0]);
328                            ObservableCollection<string> coll = pInfo.GetValue(settings, null) as ObservableCollection<string>;
329                            if (coll != null)
330                            {
331                                ComboBox comboBoxDyn = new ComboBox();
332                                comboBoxDyn.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
333                                comboBoxDyn.MouseEnter += Control_MouseEnter;
334                                comboBoxDyn.ItemsSource = coll;
335                                comboBoxDyn.SetBinding(ComboBox.SelectedIndexProperty, dataBinding);
336                                inputControl = comboBoxDyn;
337                                bInfo.CaptionGUIElement = comboBoxDyn;
338                            }
339                            break;
340                        # endregion DynamicComboBox
341                        # region CheckBox
342                        case ControlType.CheckBox:
343                            CheckBox checkBox = new CheckBox();
344                            checkBox.Margin = CONTROL_DEFAULT_MARGIN;
345                            checkBox.Content = bInfo.TaskPaneSettingsAttribute.Caption;
346                            checkBox.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
347                            checkBox.MouseEnter += Control_MouseEnter;
348                            checkBox.SetBinding(CheckBox.IsCheckedProperty, dataBinding);
349                            inputControl = checkBox;
350                            bInfo.CaptionGUIElement = checkBox;
351                            break;
352                        # endregion CheckBox
353                        # region FileDialog
354                        case ControlType.SaveFileDialog:
355                        case ControlType.OpenFileDialog:
356                            StackPanel sp = new StackPanel();
357                            sp.Orientation = Orientation.Vertical;
358
359                            TextBox fileTextBox = new TextBox();
360                            fileTextBox.Background = Brushes.LightGray;
361                            fileTextBox.IsReadOnly = true;
362                            fileTextBox.Margin = new Thickness(0, 0, 0, 5);
363                            fileTextBox.TextChanged += fileDialogTextBox_TextChanged;
364                            fileTextBox.SetBinding(TextBox.TextProperty, dataBinding);
365                            fileTextBox.SetBinding(TextBox.ToolTipProperty, dataBinding);
366
367                            fileTextBox.Tag = bInfo.TaskPaneSettingsAttribute;
368                            fileTextBox.MouseEnter += fileTextBox_MouseEnter;
369                            sp.Children.Add(fileTextBox);
370
371                            Button btn = new Button();
372                            btn.Tag = fileTextBox;
373                            if (bInfo.TaskPaneSettingsAttribute.ControlType == ControlType.SaveFileDialog) btn.Content = "Save file";
374                            else btn.Content = "Open file";
375                            btn.Click += FileDialogClick;
376                            sp.Children.Add(btn);
377                            inputControl = sp;
378                            bInfo.CaptionGUIElement = fileTextBox;
379                            break;
380                        # endregion FileDialog
381                        # region Button
382                        case ControlType.Button:
383                            Button taskPaneButton = new Button();
384                            taskPaneButton.Margin = new Thickness(0);
385                            taskPaneButton.Tag = bInfo;
386                            taskPaneButton.MouseEnter += TaskPaneButton_MouseEnter;
387                            taskPaneButton.Content = bInfo.TaskPaneSettingsAttribute.Caption;
388                            taskPaneButton.Click += TaskPaneButton_Click;
389                            inputControl = taskPaneButton;
390                            bInfo.CaptionGUIElement = taskPaneButton;
391                            break;
392                        # endregion Button
393                        # region Slider
394                        case ControlType.Slider:
395                            Slider slider = new Slider();
396                            slider.Margin = CONTROL_DEFAULT_MARGIN;
397                            slider.Orientation = Orientation.Horizontal;
398                            slider.Minimum = bInfo.TaskPaneSettingsAttribute.DoubleMinValue;
399                            slider.Maximum = bInfo.TaskPaneSettingsAttribute.DoubleMaxValue;
400                            slider.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
401                            slider.MouseEnter += Control_MouseEnter;
402                            slider.SetBinding(Slider.ValueProperty, dataBinding);
403                            inputControl = slider;
404                            bInfo.CaptionGUIElement = slider;
405                            break;
406                        # endregion Slider
407                        # region TextBoxReadOnly
408                        case ControlType.TextBoxReadOnly:
409                            TextBox textBoxReadOnly = new TextBox();
410                            textBoxReadOnly.IsReadOnly = true;
411                            textBoxReadOnly.BorderThickness = new Thickness(0);
412                            textBoxReadOnly.Background = Brushes.Transparent;
413                            textBoxReadOnly.Tag = bInfo.TaskPaneSettingsAttribute.ToolTip;
414                            textBoxReadOnly.MouseEnter += Control_MouseEnter;
415                            textBoxReadOnly.SetBinding(TextBox.TextProperty, dataBinding);
416                            inputControl = textBoxReadOnly;
417                            bInfo.CaptionGUIElement = textBoxReadOnly;
418                            break;
419                        # endregion TextBoxReadOnly
420                        #region TextBoxHidden
421                        case ControlType.TextBoxHidden:
422                            PasswordBox passwordBox = new PasswordBox();
423                            passwordBox.Tag = bInfo;
424                            passwordBox.MouseEnter += Control_MouseEnter;
425                            passwordBox.Password = bInfo.Settings.GetType().GetProperty(bInfo.TaskPaneSettingsAttribute.PropertyName).GetValue(bInfo.Settings, null) as string;
426                            passwordBox.PasswordChanged += TextBoxHidden_Changed;
427                            inputControl = passwordBox;
428                            break;
429                        #endregion TextBoxHidden
430                    }
431                    inputControl.MouseLeave += Control_MouseLeave;
432
433                    // elements in this list will be disabled while chain is running or if "disabled" state is requested
434                    if (!bInfo.TaskPaneSettingsAttribute.ChangeableWhileExecuting && bInfo.TaskPaneSettingsAttribute.ControlType != ControlType.TextBoxReadOnly)
435                    {
436                        if (!dicPluginSettingsToDisable.ContainsKey(plugin))
437                            dicPluginSettingsToDisable.Add(plugin, new List<UIElement>());
438                        dicPluginSettingsToDisable[plugin].Add(inputControl);
439                    }
440
441                    // only some elemetns need a "headline". If true element and headline have to be grouped in a stackpanel
442                    StackPanel stackPanelInputControl = null;
443                    if (bInfo.TaskPaneSettingsAttribute.ControlType != ControlType.Button && bInfo.TaskPaneSettingsAttribute.ControlType != ControlType.OpenFileDialog &&
444                        bInfo.TaskPaneSettingsAttribute.ControlType != ControlType.SaveFileDialog && bInfo.TaskPaneSettingsAttribute.ControlType != ControlType.TextBoxReadOnly &&
445                        bInfo.TaskPaneSettingsAttribute.ControlType != ControlType.CheckBox && bInfo.TaskPaneSettingsAttribute.Caption != "")
446                    {
447                        TextBox textBlock = new TextBox();
448                        textBlock.Background = Brushes.Transparent;
449                        textBlock.IsReadOnly = true;
450                        textBlock.BorderThickness = new Thickness(0);
451                        textBlock.Background = Brushes.Transparent;
452                        textBlock.Text = bInfo.TaskPaneSettingsAttribute.Caption;
453                        textBlock.ToolTip = plugin.GetPluginInfoAttribute().ToolTip + "\n[" + bInfo.TaskPaneSettingsAttribute.DisplayLevel.ToString() + "]";
454                        textBlock.Height += textBlock.Height * 1.5;
455                        stackPanelInputControl = new StackPanel();
456                        stackPanelInputControl.Margin = new Thickness(0);
457
458                        // this textBox maybe accessed later on TaskPaneSettingChanged event to set a new caption
459                        bInfo.CaptionGUIElement = textBlock;
460
461                        if (bInfo.SettingFormat != null)
462                        {
463                            textBlock.FontWeight = bInfo.SettingFormat.FontWeight;
464                            textBlock.FontStyle = bInfo.SettingFormat.FontStyle;
465                            textBlock.Foreground = bInfo.SettingFormat.ForeGround;
466                            textBlock.Background = bInfo.SettingFormat.BackGround;
467                            stackPanelInputControl.Background = bInfo.SettingFormat.BackGround;
468                        }
469
470                        // create a grid for vertical layout with definded column width
471                        if (bInfo.SettingFormat != null && bInfo.SettingFormat.Orientation == Orientation.Horizontal)
472                        {
473                            Grid grid = new Grid();
474                            grid.RowDefinitions.Add(new RowDefinition());
475                            ColumnDefinition colDef1 = new ColumnDefinition();
476                            grid.ColumnDefinitions.Add(colDef1);
477                            ColumnDefinition colDef2 = new ColumnDefinition();
478                            grid.ColumnDefinitions.Add(colDef2);
479                            colDef1.Width = bInfo.SettingFormat.WidthCol1;
480                            colDef2.Width = bInfo.SettingFormat.WidthCol2;
481                            grid.Children.Add(textBlock);
482                            grid.Children.Add(inputControl);
483                            Grid.SetRow(textBlock, 0);
484                            Grid.SetRow(inputControl, 0);
485                            Grid.SetColumn(textBlock, 0);
486                            Grid.SetColumn(inputControl, 1);
487
488                            stackPanelInputControl.Children.Add(grid);
489                        }
490                        else
491                        {
492                            // Just put headline and item into vertical stack panel
493                            stackPanelInputControl.Children.Add(textBlock);
494                            stackPanelInputControl.Children.Add(inputControl);
495                        }
496                        inputControl = stackPanelInputControl;
497                        stackPanelContent.Children.Add(stackPanelInputControl);
498                    }
499
500                    if (bInfo.SettingFormat != null)
501                    {
502                        if (bInfo.SettingFormat.Ident > 0)
503                        {
504                            StackPanel stackPanel = new StackPanel();
505                            stackPanel.Margin = new Thickness(bInfo.SettingFormat.Ident * SETTINGS_FORMAT_INDENT_OFFSET, 0, 0, 0);
506                            stackPanel.Children.Add(inputControl);
507                            inputControl = stackPanel;
508                        }
509                        // check for vertical groups
510                        if (bInfo.SettingFormat.HasVerticalGroup)
511                        {
512                            dicVerticalSubGroups.GetOrCreate(bInfo.SettingFormat.VerticalGroup).Add(new KeyValuePair<BindingInfo, UIElement>(bInfo, inputControl));
513                        }
514                    }
515
516                    // check for groups
517                    if (bInfo.TaskPaneSettingsAttribute.GroupName != null && bInfo.TaskPaneSettingsAttribute.GroupName != "")
518                    {
519                        if (!dicGroupedElements.ContainsKey(bInfo.TaskPaneSettingsAttribute.GroupName))
520                            dicGroupedElements.Add(bInfo.TaskPaneSettingsAttribute.GroupName, new List<UIElement>());
521
522                        dicGroupedElements[bInfo.TaskPaneSettingsAttribute.GroupName].Add(inputControl);
523                    }
524                    else
525                    {
526                        dicGroupedElements[emptyGroup].Add(inputControl);
527                    }
528
529                    bInfo.GUIElement = inputControl;
530
531                    string key = bInfo.TaskPaneSettingsAttribute.PropertyName != null ? bInfo.TaskPaneSettingsAttribute.PropertyName : bInfo.TaskPaneSettingsAttribute.PropertyName;
532
533                    dicAllPluginSettings.GetOrCreate(plugin.Settings).Add(
534                      bInfo.TaskPaneSettingsAttribute.PropertyName,
535                      new TaskPaneSettingsForPlugins(bInfo.TaskPaneSettingsAttribute.PropertyName, bInfo, Visibility.Visible));
536                }
537
538                #region vertical_sub_groups
539                // first create the sub groups and remove items from main dictionary if sub group is selected
540                foreach (KeyValuePair<string, List<KeyValuePair<BindingInfo, UIElement>>> kvpVerticalGrops in dicVerticalSubGroups)
541                {
542                    // TODO: place group name in vertical stack panel?
543
544                    // create grid for vertical group
545                    Grid grid = new Grid();
546                    grid.RowDefinitions.Add(new RowDefinition());
547                    // we place the group item on the position of the first vertical group item
548                    int replaceIndex = -1;
549
550                    foreach (KeyValuePair<BindingInfo, UIElement> kvp in kvpVerticalGrops.Value)
551                    {
552                        // remove from main items dic, because we create new group items
553                        if (kvp.Key.TaskPaneSettingsAttribute.HasGroupName)
554                        {
555                            if (replaceIndex == -1)
556                                replaceIndex = dicGroupedElements[kvp.Key.TaskPaneSettingsAttribute.GroupName].IndexOf(kvp.Value);
557                            dicGroupedElements[kvp.Key.TaskPaneSettingsAttribute.GroupName].Remove(kvp.Value);
558                        }
559                        else
560                        {
561                            if (replaceIndex == -1)
562                                replaceIndex = dicGroupedElements[emptyGroup].IndexOf(kvp.Value);
563                            dicGroupedElements[emptyGroup].Remove(kvp.Value);
564                        }
565                        // create new column for current item and place it there
566                        grid.ColumnDefinitions.Add(new ColumnDefinition());
567                        grid.Children.Add(kvp.Value);
568                        Grid.SetRow(kvp.Value, 0);
569                        Grid.SetColumn(kvp.Value, grid.ColumnDefinitions.Count - 1);
570                    }
571
572                    // plugin developer has to make sure, that vertical sub group items belong to the main top group, so we just take to main group of the first element
573                    // and place the grid with all items in that group
574                    if (kvpVerticalGrops.Value[0].Key.TaskPaneSettingsAttribute.HasGroupName)
575                    {
576                        dicGroupedElements[kvpVerticalGrops.Value[0].Key.TaskPaneSettingsAttribute.GroupName].Insert(replaceIndex, grid);
577                    }
578                    else
579                    {
580                        dicGroupedElements[emptyGroup].Insert(replaceIndex, grid);
581                    }
582                }
583                #endregion vertical_sub_groups
584
585                #region main_groups
586                // add all elements without groups. TODO: order is lost here           
587                //stackPanelSettingsDefault.Margin = new Thickness(EXPANDER_GROUP_LEFT_RIGHT_OFFSET, 0, EXPANDER_GROUP_LEFT_RIGHT_OFFSET, 0);
588                //foreach (UIElement ui in dicGroupedElements[emptyGroup])
589                //{
590                //    Rectangle r1 = new Rectangle();
591                //    r1.Height = CONTROL_OFFSET;
592                //    stackPanelSettingsDefault.Children.Add(r1);
593                //    stackPanelSettingsDefault.Children.Add(ui);
594                //}
595                dicGroupedElements.Remove(emptyGroup);
596
597                // now add groups with elements
598                foreach (KeyValuePair<string, List<UIElement>> kvp in dicGroupedElements)
599                {
600                    Expander exp = new Expander();
601                    exp.SetResourceReference(Expander.StyleProperty, new ComponentResourceKey(typeof(Panel), "Expander"));
602                    exp.Header = kvp.Key;
603                    StackPanel stackPanel = new StackPanel();
604                    // some offset for the settings elements just for optical reasons
605                    stackPanel.Margin = new Thickness(EXPANDER_GROUP_LEFT_RIGHT_OFFSET, 0, EXPANDER_GROUP_LEFT_RIGHT_OFFSET, 0);
606                    exp.Content = stackPanel;
607                    foreach (UIElement ui in kvp.Value)
608                    {
609                        Rectangle r1 = new Rectangle();
610                        r1.Height = CONTROL_OFFSET;
611                        stackPanel.Children.Add(r1);
612                        stackPanel.Children.Add(ui);
613                    }
614
615                    Rectangle rect = new Rectangle();
616                    rect.Height = CONTROL_OFFSET;
617                    stackPanelContent.Children.Add(rect);
618                    stackPanelContent.Children.Add(exp);
619                }
620                #endregion main_groups
621
622                if (plugin.Settings.GetTaskPaneAttributeChanged() != null)
623                {
624                    plugin.Settings.GetTaskPaneAttributeChanged().AddEventHandler(plugin.Settings, new TaskPaneAttributeChangedHandler(TaskPaneAttributeChanged));
625                }
626            }
627            catch (Exception exception)
628            {
629                GuiLogMessage(exception.Message, NotificationLevel.Error);
630            }
631        }
632
633        #region event_handler_methods
634        private void TaskPaneAttributeChanged(ISettings settings, TaskPaneAttributeChangedEventArgs args)
635        {
636            try
637            {
638                // plugin was display already
639                if (dicAllPluginSettings.ContainsKey(settings))
640                {
641                    foreach (TaskPaneAttribteContainer tpac in args.ListTaskPaneAttributeContainer)
642                    {
643                        if (dicAllPluginSettings[settings].ContainsKey(tpac.Property) && dicAllPluginSettings[settings][tpac.Property].BindingInfo != null)
644                        {
645                            dicAllPluginSettings[settings][tpac.Property].BindingInfo.GUIElement.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
646                            {
647                                dicAllPluginSettings[settings][tpac.Property].BindingInfo.GUIElement.Visibility = tpac.Visibility;
648
649                                if (tpac.TaskPaneAttribute != null)
650                                {
651                                    setCaptionAndTooltip(dicAllPluginSettings[settings][tpac.Property].BindingInfo, tpac);
652                                }
653                            }, null);
654                            dicAllPluginSettings[settings][tpac.Property].Visibility = tpac.Visibility;
655                        }
656                    }
657                }
658            }
659            catch (Exception ex)
660            {
661                GuiLogMessage(ex.Message, NotificationLevel.Error);
662            }
663        }
664
665        private void RadioButton_Checked(object sender, RoutedEventArgs e)
666        {
667            try
668            {
669                if (sender is RadioButton)
670                {
671                    RadioButton radio = sender as RadioButton;
672                    if (radio.Tag is RadioButtonListAndBindingInfo)
673                    {
674                        RadioButtonListAndBindingInfo rbl = radio.Tag as RadioButtonListAndBindingInfo;
675                        rbl.BInfo.Settings.GetType().GetProperty(rbl.BInfo.TaskPaneSettingsAttribute.PropertyName).SetValue(rbl.BInfo.Settings, rbl.List.IndexOf(radio), null);
676                    }
677                }
678            }
679            catch (Exception ex)
680            {
681                GuiLogMessage(ex.Message, NotificationLevel.Error);
682            }
683        }
684
685        // propagate changes of TextBoxHidden to ISettings instance
686        private void TextBoxHidden_Changed(object sender, RoutedEventArgs e)
687        {
688            try
689            {
690                PasswordBox pwBox = sender as PasswordBox;
691                if (pwBox != null)
692                {
693                    BindingInfo bInfo = pwBox.Tag as BindingInfo;
694                    if (bInfo != null)
695                    {
696                        bInfo.Settings.GetType().GetProperty(bInfo.TaskPaneSettingsAttribute.PropertyName).SetValue(bInfo.Settings, pwBox.Password, null);
697                    }
698                }
699            }
700            catch (Exception ex)
701            {
702                GuiLogMessage(ex.Message, NotificationLevel.Error);
703            }
704        }
705
706        private void RadioButton_PropertyChanged(object sender, PropertyChangedEventArgs e)
707        {
708            try
709            {
710                if (sender is ISettings)
711                {
712                    ISettings settings = sender as ISettings;
713                    PropertyInfo pInfo = settings.GetType().GetProperty(e.PropertyName);
714                    if (pInfo == null)
715                    {
716                        GuiLogMessage("The property \"" + e.PropertyName + "\" does not exist in your plugin settings.", NotificationLevel.Error);
717                        return;
718                    }
719                    TaskPaneAttribute[] attributes = (TaskPaneAttribute[])pInfo.GetCustomAttributes(typeof(TaskPaneAttribute), false);
720                    if (attributes.Length == 1 && attributes[0].ControlType == ControlType.RadioButton)
721                    {
722                        this.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
723                        {
724                            int value = (int)settings.GetType().GetProperty(e.PropertyName).GetValue(settings, null);
725
726                            // Avoid event loops: if plugin develop does not check that if value is != current value and fires
727                            // an event allways we have a loop. So we break this loop at this central position by reassigning
728                            // the value only if not set already.
729                            if (dicRadioButtons[settings][e.PropertyName][value].IsChecked == false || dicRadioButtons[settings][e.PropertyName][value].IsChecked == null)
730                            {
731                                foreach (RadioButton radio in dicRadioButtons[settings][e.PropertyName])
732                                {
733                                    radio.IsChecked = false;
734                                }
735                                dicRadioButtons[settings][e.PropertyName][value].IsChecked = true;
736                            }
737                        }, null);
738                    }
739                }
740            }
741            catch (Exception ex)
742            {
743                GuiLogMessage(ex.Message, NotificationLevel.Error);
744            }
745        }
746
747        private void infoMenuItem_Click(object sender, RoutedEventArgs e)
748        {
749            try
750            {
751                Clipboard.SetText(((TextBlock)((ContextMenu)((MenuItem)sender).Parent).Tag).Text.Trim());
752            }
753            catch (Exception ex)
754            {
755                GuiLogMessage(ex.Message, NotificationLevel.Error);
756            }
757        }
758
759        private void fileDialogTextBox_TextChanged(object sender, TextChangedEventArgs e)
760        {
761            try
762            {
763                ((TextBox)sender).ScrollToHorizontalOffset(int.MaxValue);
764            }
765            catch (Exception exception)
766            {
767                GuiLogMessage(exception.Message, NotificationLevel.Error);
768            }
769        }
770
771        private void hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
772        {
773            try
774            {
775                string navigateUri = ((Hyperlink)sender).NavigateUri.ToString();
776                Process.Start(navigateUri);
777                e.Handled = true;
778            }
779            catch (Exception exception)
780            {
781                GuiLogMessage(exception.Message, NotificationLevel.Error);
782            }
783        }
784
785        private void TaskPaneButton_Click(object sender, RoutedEventArgs e)
786        {
787            BindingInfo bInfo = (sender as Button).Tag as BindingInfo;
788            if (bInfo != null && bInfo.Settings != null && bInfo.TaskPaneSettingsAttribute.Method != null)
789            {
790                bInfo.TaskPaneSettingsAttribute.Method.Invoke(bInfo.Settings, null);
791            }
792        }
793
794        private void Control_MouseEnter(object sender, MouseEventArgs e)
795        {
796            try
797            {
798                if (sender is TextBox) SetHelpText((sender as TextBox).Tag as string);
799                if (sender is CheckBox) SetHelpText((sender as CheckBox).Tag as string);
800                if (sender is ComboBox) SetHelpText((sender as ComboBox).Tag as string);
801                if (sender is Slider) SetHelpText((sender as Slider).Tag as string);
802                if (sender is Button) SetHelpText((sender as Button).Tag as string);
803            }
804            catch (Exception exception)
805            {
806                GuiLogMessage(exception.Message, NotificationLevel.Error);
807            }
808        }
809
810        private void Control_MouseLeave(object sender, MouseEventArgs e)
811        {
812            textBoxTooltip.Foreground = Brushes.Transparent;
813        }
814
815        private void SetHelpText(string text)
816        {
817            try
818            {
819                textBoxTooltip.Text = text;
820                textBoxTooltip.Foreground = Brushes.Black;
821            }
822            catch (Exception exception)
823            {
824                GuiLogMessage(exception.Message, NotificationLevel.Error);
825            }
826        }
827
828        private void fileTextBox_MouseEnter(object sender, MouseEventArgs e)
829        {
830            try
831            {
832                if (sender is TextBox) SetHelpText(((sender as TextBox).Tag as TaskPaneAttribute).ToolTip);
833            }
834            catch (Exception exception)
835            {
836                GuiLogMessage(exception.Message, NotificationLevel.Error);
837            }
838        }
839
840        private void TaskPaneButton_MouseEnter(object sender, MouseEventArgs e)
841        {
842            try
843            {
844                SetHelpText(((sender as Button).Tag as BindingInfo).TaskPaneSettingsAttribute.ToolTip);
845            }
846            catch (Exception exception)
847            {
848                GuiLogMessage(exception.Message, NotificationLevel.Error);
849            }
850        }
851
852        private void FileDialogClick(object sender, RoutedEventArgs e)
853        {
854            try
855            {
856                Button btn = sender as Button;
857                TextBox tb = btn.Tag as TextBox;
858                TaskPaneAttribute tpAtt = tb.Tag as TaskPaneAttribute;
859
860                if (tpAtt.ControlType == ControlType.OpenFileDialog)
861                {
862                    OpenFileDialog ofd = new OpenFileDialog();
863                    ofd.Filter = tpAtt.FileExtension;
864                    ofd.Multiselect = false;
865                    bool? test = ofd.ShowDialog();
866                    if (test.HasValue && test.Value) tb.Text = ofd.FileName;
867                }
868                else if (tpAtt.ControlType == ControlType.SaveFileDialog)
869                {
870                    SaveFileDialog saveFileDialog = new SaveFileDialog();
871                    saveFileDialog.Filter = tpAtt.FileExtension;
872                    bool? test = saveFileDialog.ShowDialog();
873                    if (test.HasValue && test.Value) tb.Text = saveFileDialog.FileName;
874                }
875            }
876            catch (Exception exception)
877            {
878                GuiLogMessage(exception.Message, NotificationLevel.Error);
879            }
880        }
881
882        private void GuiLogMessage(string message, NotificationLevel logLevel)
883        {
884            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, null, new GuiLogEventArgs(message, null, logLevel));
885        }
886
887
888        //private void buttonShowDescription_Click(object sender, RoutedEventArgs e)
889        //{
890        //    try
891        //    {
892        //        if (OnShowPluginDescription != null)
893        //            OnShowPluginDescription(this);
894        //    }
895        //    catch (Exception ex)
896        //    {
897        //        GuiLogMessage(ex.Message, NotificationLevel.Error);
898        //    }
899        //}
900        #endregion event_handler_methods
901
902        #region privateMethods
903        private void setCaptionAndTooltip(BindingInfo bInfo, TaskPaneAttribteContainer tpac)
904        {
905            try
906            {
907
908                ((FrameworkElement)bInfo.GUIElement).ToolTip = tpac.TaskPaneAttribute.ToolTip;
909                switch (tpac.TaskPaneAttribute.ControlType)
910                {
911                    // all these elements have a TextBlock "headline", that shows the caption
912                    case ControlType.TextBox:
913                    case ControlType.NumericUpDown:
914                    case ControlType.ComboBox:
915                    case ControlType.RadioButton:
916                    case ControlType.DynamicComboBox:
917                    case ControlType.Slider:
918                        ((TextBlock)bInfo.CaptionGUIElement).Text = tpac.TaskPaneAttribute.Caption;
919                        break;
920                    case ControlType.CheckBox:
921                        ((CheckBox)bInfo.CaptionGUIElement).Content = tpac.TaskPaneAttribute.Caption;
922                        break;
923                    // no handling of these two necessary, because of hard coded name
924                    // case ControlType.SaveFileDialog:
925                    // case ControlType.OpenFileDialog:
926                    case ControlType.Button:
927                        ((Button)bInfo.CaptionGUIElement).Content = tpac.TaskPaneAttribute.Caption;
928                        break;
929                    // no change for TextBoxReadOnly needed because the property itself contains the text - makes no sense to set the value by using the attribute
930                    // case ControlType.TextBoxReadOnly:
931                    default:
932                        break;
933                }
934            }
935            catch (Exception ex)
936            {
937                GuiLogMessage(ex.Message, NotificationLevel.Error);
938            }
939        }
940        #endregion privateMethods
941    }
942
943    /// <summary>
944    /// Used for enums in comboboxes
945    /// </summary>
946    public class EnumToIntConverter : IValueConverter
947    {
948        private static EnumToIntConverter instance;
949
950        private EnumToIntConverter() { }
951
952        // singleton
953        public static EnumToIntConverter GetInstance()
954        {
955            if (instance == null)
956                instance = new EnumToIntConverter();
957
958            return instance;
959        }
960
961        // enum -> int
962        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
963        {
964            return (int)value;
965        }
966
967        // int -> enum
968        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
969        {
970            return Enum.ToObject(targetType, value);
971        }
972    }
973
974    # region helper_classes
975    public class TaskPaneSettingsForPlugins
976    {
977        public string PropertyName;
978        public BindingInfo BindingInfo;
979        public Visibility Visibility;
980        public TaskPaneSettingsForPlugins(string propertyName, BindingInfo bindingInfo, Visibility visibility)
981        {
982            if (propertyName == null || propertyName == string.Empty) throw new ArgumentException("propertyName has to be set");
983            this.PropertyName = propertyName;
984            this.BindingInfo = bindingInfo;
985        }
986    }
987
988    public class BindingInfo
989    {
990        public readonly TaskPaneAttribute TaskPaneSettingsAttribute;
991
992        public ISettings Settings;
993
994        public SettingsFormatAttribute SettingFormat;
995
996        public UIElement GUIElement;
997
998        public UIElement CaptionGUIElement;
999
1000        public BindingInfo(TaskPaneAttribute taskPaneSettingsAttribute)
1001        {
1002            this.TaskPaneSettingsAttribute = taskPaneSettingsAttribute;
1003        }
1004
1005        public BindingInfo(TaskPaneAttribute taskPaneSettingsAttribute, ISettings settings)
1006        {
1007            this.TaskPaneSettingsAttribute = taskPaneSettingsAttribute;
1008            this.Settings = settings;
1009        }
1010
1011    }
1012
1013    public class BindingInfoRibbon
1014    {
1015        public RibbonBarAttribute RibbonBarAttribute;
1016        public ISettings Settings;
1017        public string PropertyPath;
1018
1019        public BindingInfoRibbon(RibbonBarAttribute ribbonBarAttribute, string propertyPath, ISettings settings)
1020        {
1021            this.RibbonBarAttribute = ribbonBarAttribute;
1022            this.PropertyPath = propertyPath;
1023            this.Settings = settings;
1024        }
1025    }
1026
1027    public class BindingInfoComparer : IComparer<BindingInfo>
1028    {
1029        public int Compare(BindingInfo x, BindingInfo y)
1030        {
1031            if (x.TaskPaneSettingsAttribute.Order != y.TaskPaneSettingsAttribute.Order)
1032                return x.TaskPaneSettingsAttribute.Order.CompareTo(y.TaskPaneSettingsAttribute.Order);
1033            else
1034                return x.TaskPaneSettingsAttribute.Caption.CompareTo(y.TaskPaneSettingsAttribute.Caption);
1035        }
1036    }
1037
1038    public class BindingInfoRibbonComparer : IComparer<BindingInfoRibbon>
1039    {
1040        public int Compare(BindingInfoRibbon x, BindingInfoRibbon y)
1041        {
1042            if (x.RibbonBarAttribute.Order != y.RibbonBarAttribute.Order)
1043                return x.RibbonBarAttribute.Order.CompareTo(y.RibbonBarAttribute.Order);
1044            else
1045                return x.RibbonBarAttribute.Caption.CompareTo(y.RibbonBarAttribute.Caption);
1046        }
1047    }
1048
1049    public class RadioButtonListAndBindingInfo
1050    {
1051        public readonly List<RadioButton> List = null;
1052        public readonly BindingInfo BInfo = null;
1053
1054        public RadioButtonListAndBindingInfo(List<RadioButton> list, BindingInfo bInfo)
1055        {
1056            if (list == null) throw new ArgumentException("list");
1057            if (bInfo == null) throw new ArgumentException("bInfo");
1058            this.List = list;
1059            this.BInfo = bInfo;
1060        }
1061    }
1062
1063    public static class PasswordBoxAssistant
1064    {
1065        public static readonly DependencyProperty BoundPassword =
1066            DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new FrameworkPropertyMetadata(string.Empty, OnBoundPasswordChanged));
1067
1068        public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
1069            "BindPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));
1070
1071        private static readonly DependencyProperty UpdatingPassword =
1072            DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant));
1073
1074        private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
1075        {
1076            PasswordBox box = d as PasswordBox;
1077
1078            // only handle this event when the property is attached to a PasswordBox 
1079            // and when the BindPassword attached property has been set to true 
1080            if (d == null || !GetBindPassword(d))
1081            {
1082                return;
1083            }
1084
1085            // avoid recursive updating by ignoring the box's changed event 
1086            box.PasswordChanged -= HandlePasswordChanged;
1087
1088            string newPassword = (string)e.NewValue;
1089
1090            if (!GetUpdatingPassword(box))
1091            {
1092                box.Password = newPassword;
1093            }
1094
1095            box.PasswordChanged += HandlePasswordChanged;
1096        }
1097
1098        private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
1099        {
1100            // when the BindPassword attached property is set on a PasswordBox, 
1101            // start listening to its PasswordChanged event 
1102
1103            PasswordBox box = dp as PasswordBox;
1104
1105            if (box == null)
1106            {
1107                return;
1108            }
1109
1110            bool wasBound = (bool)(e.OldValue);
1111            bool needToBind = (bool)(e.NewValue);
1112
1113            if (wasBound)
1114            {
1115                box.PasswordChanged -= HandlePasswordChanged;
1116            }
1117
1118            if (needToBind)
1119            {
1120                box.PasswordChanged += HandlePasswordChanged;
1121            }
1122        }
1123
1124        private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
1125        {
1126            PasswordBox box = sender as PasswordBox;
1127
1128            // set a flag to indicate that we're updating the password 
1129            SetUpdatingPassword(box, true);
1130            // push the new password into the BoundPassword property 
1131            SetBoundPassword(box, box.Password);
1132            SetUpdatingPassword(box, false);
1133        }
1134
1135        public static void SetBindPassword(DependencyObject dp, bool value)
1136        {
1137            dp.SetValue(BindPassword, value);
1138        }
1139
1140        public static bool GetBindPassword(DependencyObject dp)
1141        {
1142            return (bool)dp.GetValue(BindPassword);
1143        }
1144
1145        public static string GetBoundPassword(DependencyObject dp)
1146        {
1147            return (string)dp.GetValue(BoundPassword);
1148        }
1149
1150        public static void SetBoundPassword(DependencyObject dp, string value)
1151        {
1152            dp.SetValue(BoundPassword, value);
1153        }
1154
1155        private static bool GetUpdatingPassword(DependencyObject dp)
1156        {
1157            return (bool)dp.GetValue(UpdatingPassword);
1158        }
1159
1160        private static void SetUpdatingPassword(DependencyObject dp, bool value)
1161        {
1162            dp.SetValue(UpdatingPassword, value);
1163        }
1164
1165    }
1166
1167    public static class DictionaryHelper
1168    {
1169        /// <summary>
1170        /// Gets or create an Dic entry.
1171        /// </summary>
1172        /// <typeparam name="TKey">The type of the key.</typeparam>
1173        /// <typeparam name="TValue">The type of the value.</typeparam>
1174        /// <param name="dictionary">The dictionary.</param>
1175        /// <param name="key">The key.</param>
1176        /// <returns>The value for the given key.</returns>
1177        public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
1178            where TValue : new()
1179        {
1180            TValue ret;
1181            if (!dictionary.TryGetValue(key, out ret))
1182            {
1183                ret = new TValue();
1184                dictionary[key] = ret;
1185            }
1186            return ret;
1187        }
1188
1189    }
1190
1191
1192    public static class StringExtensions
1193    {
1194        public static bool IsValidEmailAddress(this string s)
1195        {
1196            Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
1197            return regex.IsMatch(s);
1198        }
1199
1200        public static bool IsValidURL(this string s)
1201        {
1202            Regex regex = new Regex("(([a-zA-Z][0-9a-zA-Z+\\-\\.]*:)?/{0,2}[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?(#[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?");
1203            return regex.IsMatch(s);
1204        }
1205    }
1206
1207    #endregion helper_classes
1208}
Note: See TracBrowser for help on using the repository browser.