3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
25 // Jonathan Chambers (jonathan.chambers@ansys.com)
32 using System
.Collections
;
33 using System
.ComponentModel
.Design
;
35 using System
.Drawing
.Design
;
36 using System
.ComponentModel
;
37 using System
.Threading
;
38 using System
.Windows
.Forms
.Design
;
40 namespace System
.Windows
.Forms
.PropertyGridInternal
{
41 internal class PropertyGridView
: ScrollableControl
, IWindowsFormsEditorService
{
43 #region Private Members
44 private double splitter_percent
= .5;
45 private const int V_INDENT
= 16;
46 private int row_height
;
47 private int font_height_padding
= 3;
48 private const int RESIZE_WIDTH
= 3;
49 private const int BUTTON_WIDTH
= 25;
50 private PropertyGridTextBox grid_textbox
;
51 internal PropertyGrid property_grid
;
52 private bool resizing_grid
;
53 private int open_grid_item_count
= -1;
54 private int skipped_grid_items
;
55 private PropertyGridDropDown dropdown_form
;
56 private Form dialog_form
;
57 private ImplicitVScrollBar vbar
;
58 private StringFormat string_format
;
59 private Font bold_font
;
61 private int cached_splitter_location
;
66 public PropertyGridView (PropertyGrid propertyGrid
) {
67 property_grid
= propertyGrid
;
69 property_grid
.SelectedGridItemChanged
+= new SelectedGridItemChangedEventHandler (SelectedGridItemChanged
);
70 property_grid
.PropertyValueChanged
+= new PropertyValueChangedEventHandler (PropertyValueChanged
);
71 property_grid
.SelectedObjectsChanged
+= new EventHandler (SelectedObjectsChanged
);
73 string_format
= new StringFormat();
74 string_format
.FormatFlags
= StringFormatFlags
.NoWrap
;
75 string_format
.Trimming
= StringTrimming
.None
;
77 grid_textbox
= new PropertyGridTextBox();
78 grid_textbox
.DropDownButtonClicked
+=new EventHandler(DropDownButtonClicked
);
79 grid_textbox
.DialogButtonClicked
+=new EventHandler(DialogButtonClicked
);
81 dropdown_form
= new PropertyGridDropDown();
82 dropdown_form
.FormBorderStyle
= FormBorderStyle
.None
;
83 dropdown_form
.StartPosition
= FormStartPosition
.Manual
;
84 dropdown_form
.ShowInTaskbar
= false;
86 dialog_form
= new Form ();
87 dialog_form
.StartPosition
= FormStartPosition
.Manual
;
88 dialog_form
.FormBorderStyle
= FormBorderStyle
.None
;
89 dialog_form
.ShowInTaskbar
= false;
91 skipped_grid_items
= 0;
92 row_height
= Font
.Height
+ font_height_padding
;
94 grid_textbox
.Visible
= false;
95 grid_textbox
.Font
= this.Font
;
96 grid_textbox
.BackColor
= this.BackColor
;
97 // Not working at all, used to??
98 grid_textbox
.Validating
+= new CancelEventHandler(TextBoxValidating
);
99 grid_textbox
.ToggleValue
+=new EventHandler(grid_textbox_ToggleValue
);
100 this.Controls
.Add(grid_textbox
);
102 vbar
= new ImplicitVScrollBar();
103 vbar
.Visible
= false;
104 vbar
.ValueChanged
+=new EventHandler(HandleValueChanged
);
105 vbar
.Dock
= DockStyle
.Right
;
106 this.Controls
.AddImplicit(vbar
);
108 resizing_grid
= false;
110 bold_font
= new Font(this.Font
, FontStyle
.Bold
);
112 ForeColorChanged
+=new EventHandler(RedrawEvent
);
113 BackColorChanged
+=new System
.EventHandler(RedrawEvent
);
114 FontChanged
+=new EventHandler(RedrawEvent
);
116 SetStyle(ControlStyles
.Selectable
, true);
118 SetStyle(ControlStyles
.DoubleBuffer
, true);
120 SetStyle(ControlStyles
.UserPaint
, true);
121 SetStyle(ControlStyles
.AllPaintingInWmPaint
, true);
123 SetStyle(ControlStyles
.ResizeRedraw
, true);
129 #region Protected Instance Methods
131 protected override void OnFontChanged(EventArgs e
) {
132 base.OnFontChanged (e
);
134 bold_font
= new Font(this.Font
, FontStyle
.Bold
);
135 row_height
= Font
.Height
+ font_height_padding
;
138 void InvalidateGridItemLabel (GridItem item
)
140 Invalidate (new Rectangle (0, item
.Top
, SplitterLocation
, row_height
));
144 void InvalidateGridItem (GridItem item
)
146 Invalidate (new Rectangle (0, item
.Top
, Width
, row_height
));
150 void CalcHeightOfGridItems (GridItemCollection col
, ref int amount
)
152 foreach (GridItem i
in col
) {
153 amount
+= row_height
;
155 CalcHeightOfGridItems (i
.GridItems
, ref amount
);
159 public void RedrawBelowItemOnExpansion (GridItem item
)
161 grid_textbox_Hide ();
163 Invalidate(new Rectangle (0, item
.Top
, Width
, Height
- item
.Top
));
165 // ugh, we need to recurse down into all our
166 // group items to figure out the space to
170 CalcHeightOfGridItems (item
.GridItems
, ref amount
);
173 XplatUI
.ScrollWindow (Handle
,
174 new Rectangle (0, item
.Top
+ row_height
,
175 Width
, Height
- item
.Top
- row_height
),
179 XplatUI
.ScrollWindow (Handle
,
180 new Rectangle (0, item
.Top
+ row_height
,
181 Width
, Height
- item
.Top
- row_height
),
184 InvalidateGridItem (item
);
187 grid_textbox_Show (property_grid
.SelectedGridItem
);
190 protected override void OnDoubleClick(EventArgs e
) {
191 if (property_grid
.SelectedGridItem
.Expandable
) {
192 property_grid
.SelectedGridItem
.Expanded
= !property_grid
.SelectedGridItem
.Expanded
;
195 GridItem item
= property_grid
.SelectedGridItem
;
196 if (item
.GridItemType
== GridItemType
.Property
197 && !item
.PropertyDescriptor
.IsReadOnly
) {
204 protected override void OnPaint(PaintEventArgs e
) {
205 // Decide if we need a scrollbar
206 open_grid_item_count
= 0;
209 e
.Graphics
.FillRectangle (ThemeEngine
.Current
.ResPool
.GetSolidBrush (BackColor
), ClientRectangle
);
211 int yLoc
= -vbar
.Value
*row_height
;
213 if (property_grid
.root_grid_item
!= null)
214 DrawGridItems(property_grid
.root_grid_item
.GridItems
, e
, 1, ref yLoc
);
219 protected override void OnMouseWheel(MouseEventArgs e
) {
220 if (vbar
== null || !vbar
.Visible
) {
225 vbar
.Value
= Math
.Min(vbar
.Value
+ SystemInformation
.MouseWheelScrollLines
, vbar
.Maximum
);
227 vbar
.Value
= Math
.Max(0, vbar
.Value
- SystemInformation
.MouseWheelScrollLines
);
229 base.OnMouseWheel (e
);
233 protected override void OnMouseMove (MouseEventArgs e
) {
234 if (property_grid
.root_grid_item
== null)
238 int loc
= Math
.Max(e
.X
,2*V_INDENT
);
239 SplitterPercent
= 1.0*loc
/Width
;
241 if (e
.X
> SplitterLocation
- RESIZE_WIDTH
&& e
.X
< SplitterLocation
+ RESIZE_WIDTH
)
242 this.Cursor
= Cursors
.SizeWE
;
244 this.Cursor
= Cursors
.Default
;
245 base.OnMouseMove (e
);
248 protected override void OnMouseDown (MouseEventArgs e
) {
249 if (property_grid
.root_grid_item
== null)
252 if (e
.X
> SplitterLocation
- RESIZE_WIDTH
&& e
.X
< SplitterLocation
+ RESIZE_WIDTH
) {
253 resizing_grid
= true;
256 int offset
= -vbar
.Value
*row_height
;
257 GridItem foundItem
= GetSelectedGridItem(property_grid
.root_grid_item
.GridItems
, e
.Y
, ref offset
);
259 if (foundItem
!= null) {
260 if (foundItem
.Expandable
) {
261 if (e
.X
>=3 && e
.X
<= 11 && (e
.Y
% row_height
>= row_height
/2-2 && e
.Y
% row_height
<= row_height
/2+4)) {
262 foundItem
.Expanded
= !foundItem
.Expanded
;
265 this.property_grid
.SelectedGridItem
= foundItem
;
268 base.OnMouseDown (e
);
272 protected override void OnMouseUp (MouseEventArgs e
) {
273 resizing_grid
= false;
277 protected override void OnResize(EventArgs e
) {
279 grid_textbox
.Hide ();
280 ResumeLayout (false);
283 // we need to explicitly handle this redraw
284 // before getting to the scrollwindow, or we
285 // end up having to redraw the entire item
286 // value area because the exposed areas are
293 if (cached_splitter_location
!= SplitterLocation
) {
294 int x
= cached_splitter_location
> SplitterLocation
? SplitterLocation
: cached_splitter_location
;
295 XplatUI
.ScrollWindow (Handle
,
296 new Rectangle (x
, 0, Width
- x
- (vbar
.Visible
? vbar
.Width
: 0), Height
),
297 SplitterLocation
- cached_splitter_location
, 0, false);
300 cached_splitter_location
= SplitterLocation
;
303 grid_textbox_Show (property_grid
.SelectedGridItem
);
304 ResumeLayout (false);
307 private void UnfocusSelection ()
312 protected override bool ProcessDialogKey (Keys keyData
) {
313 GridItem selectedItem
= property_grid
.SelectedGridItem
;
314 if (selectedItem
!= null
315 && grid_textbox
.Visible
316 /* if the textbox has focus? */) {
319 SetPropertyValue(selectedItem
.PropertyDescriptor
.Converter
.ConvertFromString(grid_textbox
.Text
));
323 grid_textbox
.Text
= selectedItem
.PropertyDescriptor
.Converter
.ConvertToString(selectedItem
.Value
);
330 return base.ProcessDialogKey (keyData
);
334 protected override bool IsInputKey (Keys keyData
) {
352 private GridEntry
MoveUpFromItem (GridEntry item
, int up_count
)
354 GridItemCollection items
;
357 /* move back up the visible rows (and up the hierarchy as necessary) until
358 up_count == 0, or we reach the top of the display */
359 while (up_count
> 0) {
360 items
= item
.Parent
!= null ? item
.Parent
.GridItems
: property_grid
.root_grid_item
.GridItems
;
361 index
= items
.IndexOf (item
);
364 if (item
.Parent
.GridItemType
== GridItemType
.Root
) // we're at the top row
366 item
= (GridEntry
)item
.Parent
;
370 GridEntry prev_item
= (GridEntry
)items
[index
-1];
371 if (prev_item
.Expandable
&& prev_item
.Expanded
) {
372 item
= (GridEntry
)prev_item
.GridItems
[prev_item
.GridItems
.Count
- 1];
383 private GridEntry
MoveDownFromItem (GridEntry item
, int down_count
)
385 while (down_count
> 0) {
386 /* if we're a parent node and we're expanded, move to our first child */
387 if (item
.Expandable
&& item
.Expanded
) {
388 item
= (GridEntry
)item
.GridItems
[0];
392 GridItem searchItem
= item
;
393 GridItemCollection searchItems
= searchItem
.Parent
.GridItems
;
394 int searchIndex
= searchItems
.IndexOf (searchItem
);
396 while (searchIndex
== searchItems
.Count
- 1) {
397 searchItem
= searchItem
.Parent
;
399 if (searchItem
== null || searchItem
.Parent
== null)
402 searchItems
= searchItem
.Parent
.GridItems
;
403 searchIndex
= searchItems
.IndexOf (searchItem
);
406 if (searchIndex
== searchItems
.Count
- 1) {
407 /* if we got all the way back to the root with no nodes after
408 us, the original item was the last one */
412 item
= (GridEntry
)searchItems
[searchIndex
+1];
421 protected override void OnKeyDown(KeyEventArgs e
) {
422 GridEntry selectedItem
= (GridEntry
)property_grid
.SelectedGridItem
;
424 if (selectedItem
== null) {
425 /* XXX not sure what MS does, but at least we shouldn't crash */
430 switch (e
.KeyData
& Keys
.KeyCode
) {
433 if (SplitterLocation
> 2 * V_INDENT
)
434 SplitterPercent
-= 0.01;
440 /* if the node is expandable and is expanded, collapse it.
441 otherwise, act just like the user pressed up */
442 if (selectedItem
.Expandable
&& selectedItem
.Expanded
) {
443 selectedItem
.Expanded
= false;
452 if (SplitterLocation
< Width
)
453 SplitterPercent
+= 0.01;
459 /* if the node is expandable and not expanded, expand it.
460 otherwise, act just like the user pressed down */
461 if (selectedItem
.Expandable
&& !selectedItem
.Expanded
) {
462 selectedItem
.Expanded
= true;
470 /* toggle the expanded state of the selected item */
471 if (selectedItem
.Expandable
) {
472 selectedItem
.Expanded
= !selectedItem
.Expanded
;
477 property_grid
.SelectedGridItem
= MoveUpFromItem (selectedItem
, 1);
481 property_grid
.SelectedGridItem
= MoveDownFromItem (selectedItem
, 1);
485 property_grid
.SelectedGridItem
= MoveUpFromItem (selectedItem
, vbar
.LargeChange
);
489 property_grid
.SelectedGridItem
= MoveDownFromItem (selectedItem
, vbar
.LargeChange
);
493 /* find the last, most deeply nested visible item */
494 GridEntry item
= (GridEntry
)property_grid
.root_grid_item
.GridItems
[property_grid
.root_grid_item
.GridItems
.Count
- 1];
495 while (item
.Expandable
&& item
.Expanded
)
496 item
= (GridEntry
)item
.GridItems
[item
.GridItems
.Count
- 1];
497 property_grid
.SelectedGridItem
= item
;
501 property_grid
.SelectedGridItem
= property_grid
.root_grid_item
.GridItems
[0];
511 #region Private Helper Methods
513 private int SplitterLocation
{
515 return (int)(splitter_percent
*Width
);
519 private double SplitterPercent
{
521 int old_splitter_location
= SplitterLocation
;
523 splitter_percent
= Math
.Max(Math
.Min(value, .9),.1);
525 if (old_splitter_location
!= SplitterLocation
) {
526 grid_textbox_Hide ();
527 int x
= old_splitter_location
> SplitterLocation
? SplitterLocation
: old_splitter_location
;
529 Invalidate(new Rectangle (x
, 0, Width
- x
- (vbar
.Visible
? vbar
.Width
: 0), Height
));
531 XplatUI
.ScrollWindow (Handle
,
532 new Rectangle (x
, 0, Width
- x
- (vbar
.Visible
? vbar
.Width
: 0), Height
),
533 SplitterLocation
- old_splitter_location
, 0, false);
536 grid_textbox_Show (property_grid
.SelectedGridItem
);
540 cached_splitter_location
= SplitterLocation
;
544 return splitter_percent
;
548 private GridItem
GetSelectedGridItem (GridItemCollection grid_items
, int y
, ref int current
) {
549 foreach (GridItem child_grid_item
in grid_items
) {
550 if (y
> current
&& y
< current
+ row_height
) {
551 return child_grid_item
;
553 current
+= row_height
;
554 if (child_grid_item
.Expanded
) {
555 GridItem foundItem
= GetSelectedGridItem(child_grid_item
.GridItems
, y
, ref current
);
556 if (foundItem
!= null)
563 private void UpdateScrollBar() {
564 int visible_rows
= this.ClientRectangle
.Height
/row_height
;
565 if (open_grid_item_count
> visible_rows
) {
567 vbar
.SmallChange
= 1;
569 vbar
.Maximum
= open_grid_item_count
-1;
570 vbar
.LargeChange
= visible_rows
;
573 vbar
.Visible
= false;
580 private void DrawGridItems(GridItemCollection grid_items
, PaintEventArgs pevent
, int depth
, ref int yLoc
) {
581 foreach (GridItem grid_item
in grid_items
) {
582 DrawGridItem (grid_item
, pevent
, depth
, ref yLoc
);
583 if (grid_item
.Expanded
)
584 DrawGridItems(grid_item
.GridItems
, pevent
, (grid_item
.GridItemType
== GridItemType
.Category
) ? depth
: depth
+1, ref yLoc
);
588 private void DrawGridItemLabel(GridItem grid_item
, PaintEventArgs pevent
, int depth
, Rectangle rect
) {
589 Font font
= this.Font
;
592 if (grid_item
.GridItemType
== GridItemType
.Category
) {
594 brush
= SystemBrushes
.ControlDark
;
596 pevent
.Graphics
.DrawString (grid_item
.Label
, font
, brush
, rect
.X
+ 1, rect
.Y
+ 2);
597 if (grid_item
== property_grid
.SelectedGridItem
) {
598 SizeF size
= pevent
.Graphics
.MeasureString (grid_item
.Label
, font
);
599 ControlPaint
.DrawFocusRectangle (pevent
.Graphics
, new Rectangle(rect
.X
+ 1, rect
.Y
+2, (int)size
.Width
, (int)size
.Height
));
603 if (grid_item
== property_grid
.SelectedGridItem
) {
604 Rectangle highlight
= rect
;
606 highlight
.X
-= V_INDENT
;
607 highlight
.Width
+= V_INDENT
;
609 pevent
.Graphics
.FillRectangle (SystemBrushes
.Highlight
, highlight
);
611 brush
= SystemBrushes
.HighlightText
;
614 brush
= SystemBrushes
.WindowText
;
615 if (grid_item
.PropertyDescriptor
.IsReadOnly
616 && !grid_item
.Expandable
)
617 brush
= SystemBrushes
.InactiveCaption
;
621 pevent
.Graphics
.DrawString (grid_item
.Label
, font
, brush
,
622 new Rectangle (rect
.X
+ 1, rect
.Y
+ 2, rect
.Width
- 2, rect
.Height
- 2),
626 private void DrawGridItemValue(GridItem grid_item
, PaintEventArgs pevent
, int depth
, Rectangle rect
) {
628 if (grid_item
.PropertyDescriptor
!= null) {
630 bool paintsValue
= false;
631 UITypeEditor editor
= (UITypeEditor
)grid_item
.PropertyDescriptor
.GetEditor(typeof(UITypeEditor
));
632 if (editor
!= null) {
633 paintsValue
= editor
.GetPaintValueSupported();
636 int xLoc
= SplitterLocation
+1;
638 pevent
.Graphics
.DrawRectangle(Pens
.Black
, SplitterLocation
+2,rect
.Y
+2, 20, row_height
-4);
640 editor
.PaintValue(grid_item
.Value
, pevent
.Graphics
, new Rectangle(SplitterLocation
+3,rect
.Y
+3, 19, row_height
-5));
648 if (grid_item
.PropertyDescriptor
.Converter
!= null) {
649 Font font
= this.Font
;
652 string value = grid_item
.PropertyDescriptor
.Converter
.ConvertToString(grid_item
.Value
);
653 if (((GridEntry
)grid_item
).CanResetValue ())
656 brush
= SystemBrushes
.WindowText
;
657 if (grid_item
.PropertyDescriptor
.IsReadOnly
658 && !grid_item
.Expandable
)
659 brush
= SystemBrushes
.InactiveCaption
;
661 pevent
.Graphics
.DrawString(value, font
,
663 new RectangleF(xLoc
, rect
.Y
+2,
664 ClientRectangle
.Width
-(xLoc
), row_height
),string_format
);
667 Console
.WriteLine("No converter for type {0}",grid_item
.PropertyDescriptor
.PropertyType
);
676 private void DrawGridItem (GridItem grid_item
, PaintEventArgs pevent
, int depth
, ref int yLoc
) {
677 if (yLoc
> -row_height
&& yLoc
< ClientRectangle
.Height
) {
680 pevent
.Graphics
.FillRectangle (ThemeEngine
.Current
.ResPool
.GetSolidBrush (property_grid
.LineColor
),
681 0, yLoc
, V_INDENT
, row_height
);
683 if (grid_item
.Expandable
) {
684 grid_item
.PlusMinusBounds
= DrawPlusMinus(pevent
.Graphics
, 3, yLoc
+row_height
/2-3, grid_item
.Expanded
, grid_item
.GridItemType
== GridItemType
.Category
);
687 if (grid_item
.GridItemType
== GridItemType
.Category
) {
688 pevent
.Graphics
.FillRectangle (ThemeEngine
.Current
.ResPool
.GetSolidBrush (property_grid
.LineColor
), depth
*V_INDENT
,yLoc
,ClientRectangle
.Width
-(depth
*V_INDENT
), row_height
);
691 DrawGridItemLabel(grid_item
, pevent
,
693 new Rectangle(depth
* V_INDENT
, yLoc
, SplitterLocation
- depth
* V_INDENT
, row_height
));
694 DrawGridItemValue(grid_item
, pevent
,
696 new Rectangle(SplitterLocation
+ 2 , yLoc
, ClientRectangle
.Width
- SplitterLocation
- 2 - (vbar
.Visible
? vbar
.Width
: 0), row_height
));
698 if (grid_item
.GridItemType
!= GridItemType
.Category
) {
699 Pen pen
= ThemeEngine
.Current
.ResPool
.GetPen(property_grid
.LineColor
);
700 // vertical divider line
701 pevent
.Graphics
.DrawLine(pen
, SplitterLocation
, yLoc
, SplitterLocation
, yLoc
+ row_height
);
703 // draw the horizontal line
704 pevent
.Graphics
.DrawLine(pen
, 0, yLoc
+ row_height
, ClientRectangle
.Width
, yLoc
+ row_height
);
707 grid_item
.Top
= yLoc
;
709 open_grid_item_count
++;
712 private Rectangle
DrawPlusMinus (Graphics g
, int x
, int y
, bool expanded
, bool category
) {
713 Rectangle bounds
= new Rectangle(x
, y
, 8, 8);
714 if (!category
) g
.FillRectangle (Brushes
.White
, bounds
);
715 Pen pen
= ThemeEngine
.Current
.ResPool
.GetPen (property_grid
.ViewForeColor
);
716 g
.DrawRectangle (pen
, bounds
);
717 g
.DrawLine (pen
, x
+2, y
+4, x
+ 6, y
+4);
719 g
.DrawLine (pen
, x
+4, y
+2, x
+4, y
+6);
726 #region Event Handling
727 private void RedrawEvent (object sender
, System
.EventArgs e
) {
731 private void TextBoxValidating (object sender
, CancelEventArgs e
) {
732 if (this.property_grid
.SelectedGridItem
!= null) {
733 PropertyDescriptor desc
= property_grid
.SelectedGridItem
.PropertyDescriptor
;
736 if (desc
.Converter
!= null) {
737 SetPropertyValue(desc
.Converter
.ConvertFromString(grid_textbox
.Text
));
740 Console
.WriteLine("No converter for type {0}",desc
.PropertyType
);
744 Console
.WriteLine("Error converting string");
752 private void ToggleValue() {
753 if (property_grid
.SelectedGridItem
.GridItemType
== GridItemType
.Property
) {
754 if (property_grid
.SelectedGridItem
.PropertyDescriptor
!= null) {
755 if (property_grid
.SelectedGridItem
.PropertyDescriptor
.PropertyType
== typeof(bool))
756 SetPropertyValue(!(bool)property_grid
.SelectedGridItem
.Value
);
757 else if (property_grid
.SelectedGridItem
.PropertyDescriptor
.Converter
.GetStandardValuesSupported()){
758 System
.ComponentModel
.TypeConverter
.StandardValuesCollection coll
=
759 (System
.ComponentModel
.TypeConverter
.StandardValuesCollection
)property_grid
.SelectedGridItem
.PropertyDescriptor
.Converter
.GetStandardValues();
760 for (int i
= 0; i
< coll
.Count
; i
++) {
761 if (property_grid
.SelectedGridItem
.Value
.Equals(coll
[i
])){
762 if (i
< coll
.Count
-1)
763 SetPropertyValue(coll
[i
+1]);
765 SetPropertyValue(coll
[0]);
775 private void listBox_MouseUp(object sender
, MouseEventArgs e
) {
776 AcceptListBoxSelection (sender
);
779 private void listBox_KeyDown(object sender
, KeyEventArgs e
)
781 switch (e
.KeyData
& Keys
.KeyCode
) {
783 AcceptListBoxSelection (sender
);
791 void AcceptListBoxSelection (object sender
) {
792 if (this.property_grid
.SelectedGridItem
!= null) {
793 PropertyDescriptor desc
= property_grid
.SelectedGridItem
.PropertyDescriptor
;
795 SetPropertyValue(((ListBox
)sender
).SelectedItem
);
801 private void SetPropertyValue(object newVal
) {
802 if (property_grid
.SelectedGridItem
== null)
805 PropertyDescriptor desc
= property_grid
.SelectedGridItem
.PropertyDescriptor
;
809 for (int i
= 0; i
< ((GridEntry
)property_grid
.SelectedGridItem
).SelectedObjects
.Length
; i
++) {
810 object target
= property_grid
.GetTarget (property_grid
.SelectedGridItem
, i
);
811 desc
.SetValue(target
, newVal
);
815 private void DropDownButtonClicked (object sender
, EventArgs e
) {
816 UITypeEditor editor
= property_grid
.SelectedGridItem
.PropertyDescriptor
.GetEditor (typeof (UITypeEditor
)) as UITypeEditor
;
817 if (editor
== null) {
818 if (dropdown_form
.Visible
) {
822 TypeConverter converter
= property_grid
.SelectedGridItem
.PropertyDescriptor
.Converter
;
823 ICollection std_values
;
825 if (!converter
.GetStandardValuesSupported ())
828 std_values
= converter
.GetStandardValues();
829 if (std_values
== null)
832 ListBox listBox
= new ListBox();
833 listBox
.BorderStyle
= BorderStyle
.FixedSingle
;
834 int selected_index
= 0;
836 object selected_value
= property_grid
.SelectedGridItem
.Value
;
837 foreach (object obj
in std_values
) {
838 listBox
.Items
.Add(obj
);
839 if (selected_value
!= null && selected_value
.Equals(obj
))
843 listBox
.Height
= row_height
* Math
.Min (listBox
.Items
.Count
, 15);
844 listBox
.SelectedIndex
= selected_index
;
845 listBox
.KeyDown
+= new KeyEventHandler(listBox_KeyDown
);
846 listBox
.MouseUp
+=new MouseEventHandler(listBox_MouseUp
);
848 DropDownControl (listBox
);
850 } else { // use editor
851 SetPropertyValueFromUITypeEditor (editor
);
855 void SetPropertyValueFromUITypeEditor (UITypeEditor editor
)
857 ServiceContainer service_container
= new ServiceContainer ();
858 service_container
.AddService (typeof (IWindowsFormsEditorService
), this);
859 object initial_value
= property_grid
.SelectedGridItem
.Value
;
860 object value = editor
.EditValue (
861 (ITypeDescriptorContext
)property_grid
.SelectedGridItem
,
864 if (!Object
.Equals (value, initial_value
)) {
865 SetPropertyValue (value);
869 private void DialogButtonClicked(object sender
, EventArgs e
) {
870 UITypeEditor editor
= property_grid
.SelectedGridItem
.PropertyDescriptor
.GetEditor (typeof (UITypeEditor
)) as UITypeEditor
;
872 SetPropertyValueFromUITypeEditor (editor
);
875 private void HandleValueChanged(object sender
, EventArgs e
) {
876 if (vbar
.Value
<= 0) {
879 if (vbar
.Value
> vbar
.Maximum
-ClientRectangle
.Height
/row_height
) {
880 vbar
.Value
= vbar
.Maximum
-ClientRectangle
.Height
/row_height
+1;
883 int scroll_amount
= (skipped_grid_items
-vbar
.Value
)*row_height
;
885 if (scroll_amount
== 0)
888 grid_textbox_Hide ();
890 skipped_grid_items
= vbar
.Value
;
891 XplatUI
.ScrollWindow(Handle
, 0, scroll_amount
, false);
897 if (property_grid
.SelectedGridItem
!= null)
898 grid_textbox_Show (property_grid
.SelectedGridItem
);
901 private void grid_textbox_ToggleValue(object sender
, EventArgs e
) {
902 if (!property_grid
.SelectedGridItem
.PropertyDescriptor
.IsReadOnly
) {
908 internal void grid_textbox_Show (GridItem forItem
)
910 if (forItem
== null || forItem
.PropertyDescriptor
== null)
915 if (((GridEntry
)forItem
).CanResetValue ())
916 grid_textbox
.Font
= bold_font
;
918 grid_textbox
.Font
= this.Font
;
920 grid_textbox
.ReadOnly
= false;
921 grid_textbox
.DropDownButtonVisible
= false;
922 grid_textbox
.DialogButtonVisible
= false;
924 bool paintsValue
= false;
925 UITypeEditor editor
= (UITypeEditor
)forItem
.PropertyDescriptor
.GetEditor(typeof(UITypeEditor
));
926 if (editor
!= null) {
927 paintsValue
= editor
.GetPaintValueSupported();
930 if (editor
!= null) {
931 UITypeEditorEditStyle style
= editor
.GetEditStyle();
934 case UITypeEditorEditStyle
.DropDown
:
935 grid_textbox
.DropDownButtonVisible
= true;
937 case UITypeEditorEditStyle
.Modal
:
938 grid_textbox
.DialogButtonVisible
= true;
944 if (forItem
.PropertyDescriptor
.Converter
!= null) {
945 if (forItem
.PropertyDescriptor
.Converter
.GetStandardValuesSupported()) {
947 grid_textbox
.DropDownButtonVisible
= true;
948 grid_textbox
.ReadOnly
= true;
952 Console
.WriteLine("Converter not available for type {0}",forItem
.PropertyDescriptor
.PropertyType
);
960 grid_textbox
.ReadOnly
= grid_textbox
.ReadOnly
|| forItem
.PropertyDescriptor
.IsReadOnly
;
962 int xloc
= SplitterLocation
+ 1 + (paintsValue
? 27 : 0);
963 grid_textbox
.SetBounds (xloc
,
965 ClientRectangle
.Width
- xloc
- (vbar
.Visible
? vbar
.Width
: 0),
967 grid_textbox
.Visible
= true;
969 ResumeLayout (false);
972 private void grid_textbox_Hide ()
975 grid_textbox
.Bounds
= Rectangle
.Empty
;
976 grid_textbox
.Visible
= false;
977 ResumeLayout (false);
980 void EnsureItemIsVisible (GridItem item
)
983 // the new item is above the viewable area
984 vbar
.Value
+= item
.Top
/ row_height
;
986 else if (item
.Top
+ row_height
> Height
) {
987 // the new item is below the viewable area
988 vbar
.Value
+= ((item
.Top
+ row_height
) - Height
) / row_height
+ 1;
996 private void SelectedObjectsChanged (object sender
, EventArgs args
) {
997 grid_textbox_Hide ();
1000 private void SelectedGridItemChanged(object sender
, SelectedGridItemChangedEventArgs e
) {
1001 if (e
.OldSelection
!= null)
1002 InvalidateGridItemLabel (e
.OldSelection
);
1003 InvalidateGridItemLabel (e
.NewSelection
);
1005 EnsureItemIsVisible (e
.NewSelection
);
1007 if (e
.NewSelection
.GridItemType
== GridItemType
.Property
) {
1008 if (e
.NewSelection
.PropertyDescriptor
!= null) {
1010 if (e
.NewSelection
.Value
== null)
1011 grid_textbox
.Text
= "";
1013 grid_textbox
.Text
= e
.NewSelection
.PropertyDescriptor
.Converter
.ConvertToString(e
.NewSelection
.Value
);
1014 if (((GridEntry
)e
.NewSelection
).CanResetValue ())
1015 grid_textbox
.Font
= bold_font
;
1017 grid_textbox
.Font
= this.Font
;
1019 grid_textbox_Show (e
.NewSelection
);
1023 grid_textbox_Hide ();
1027 private void PropertyValueChanged(object s
, PropertyValueChangedEventArgs e
) {
1028 if (e
.ChangedItem
.PropertyDescriptor
!= null) {
1029 grid_textbox
.Text
= e
.ChangedItem
.PropertyDescriptor
.Converter
.ConvertToString(e
.ChangedItem
.Value
);
1030 if (((GridEntry
)e
.ChangedItem
).CanResetValue())
1031 grid_textbox
.Font
= bold_font
;
1033 grid_textbox
.Font
= this.Font
;
1037 private void DropDownControl(Control control
, bool block
) {
1040 dropdown_form
.Size
= control
.Size
;
1041 control
.Dock
= DockStyle
.Fill
;
1042 dropdown_form
.Controls
.Clear();
1043 dropdown_form
.Controls
.Add(control
);
1044 dropdown_form
.Location
= PointToScreen(new Point(SplitterLocation
,grid_textbox
.Location
.Y
+row_height
));
1045 dropdown_form
.Width
= ClientRectangle
.Width
- SplitterLocation
- (vbar
.Visible
? vbar
.Width
: 0);
1047 FindForm ().AddOwnedForm (dropdown_form
);
1049 dropdown_form
.Show();
1052 System
.Windows
.Forms
.MSG msg
= new MSG();
1053 queue_id
= XplatUI
.StartLoop(Thread
.CurrentThread
);
1054 while (dropdown_form
.Visible
&& XplatUI
.GetMessage(queue_id
, ref msg
, IntPtr
.Zero
, 0, 0)) {
1056 if ((msg
.message
== Msg
.WM_NCLBUTTONDOWN
||
1057 msg
.message
== Msg
.WM_NCMBUTTONDOWN
||
1058 msg
.message
== Msg
.WM_NCRBUTTONDOWN
||
1059 msg
.message
== Msg
.WM_LBUTTONDOWN
||
1060 msg
.message
== Msg
.WM_MBUTTONDOWN
||
1061 msg
.message
== Msg
.WM_RBUTTONDOWN
)
1062 && !HwndInControl (dropdown_form
, msg
.hwnd
)) {
1066 XplatUI
.TranslateMessage(ref msg
);
1067 XplatUI
.DispatchMessage(ref msg
);
1072 private bool HwndInControl (Control c
, IntPtr hwnd
)
1074 if (hwnd
== c
.window
.Handle
)
1076 foreach (Control cc
in c
.Controls
.GetAllControls ())
1077 if (HwndInControl (cc
, hwnd
))
1084 #region IWindowsFormsEditorService Members
1086 public void CloseDropDown() {
1087 Control c
= dropdown_form
.Controls
[0];
1089 dropdown_form
.Hide();
1092 public void DropDownControl(Control control
) {
1093 DropDownControl (control
, true);
1096 public System
.Windows
.Forms
.DialogResult
ShowDialog(Form dialog
) {
1097 return dialog
.ShowDialog(this);
1105 internal class PropertyGridDropDown
: Form
{
1106 protected override CreateParams CreateParams
{
1108 CreateParams cp
= base.CreateParams
;
1109 cp
.Style
= unchecked ((int)(WindowStyles
.WS_POPUP
| WindowStyles
.WS_CLIPSIBLINGS
| WindowStyles
.WS_CLIPCHILDREN
));
1110 cp
.ExStyle
|= (int)(WindowExStyles
.WS_EX_TOOLWINDOW
| WindowExStyles
.WS_EX_TOPMOST
);