5 // Moonlight List (moonlight-list@lists.ximian.com)
7 // Copyright 2008 Novell, Inc.
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System
.Collections
.Specialized
;
30 using System
.Windows
.Input
;
32 namespace System
.Windows
.Controls
.Primitives
{
33 public abstract class Selector
: ItemsControl
{
34 internal const string TemplateScrollViewerName
= "ScrollViewer";
36 internal static readonly DependencyProperty IsSelectionActiveProperty
=
37 DependencyProperty
.RegisterReadOnlyCore ("IsSelectionActive", typeof(bool), typeof(Selector
), null);
39 public static readonly DependencyProperty SelectedIndexProperty
=
40 DependencyProperty
.RegisterCore ("SelectedIndex", typeof(int), typeof(Selector
),
41 new PropertyMetadata(-1, new PropertyChangedCallback(OnSelectedIndexChanged
)));
43 static void OnSelectedIndexChanged (DependencyObject o
, DependencyPropertyChangedEventArgs e
)
45 ((Selector
) o
).SelectedIndexChanged (o
, e
);
48 // This is not a core property because it is a non-parenting property
49 public static readonly DependencyProperty SelectedItemProperty
=
50 DependencyProperty
.Register ("SelectedItem", typeof(object), typeof(Selector
),
51 new PropertyMetadata(new PropertyChangedCallback(OnSelectedItemChanged_cb
)));
54 static void OnSelectedItemChanged_cb (DependencyObject o
, DependencyPropertyChangedEventArgs e
)
56 ((Selector
) o
).SelectedItemChanged (o
, e
);
59 internal static void OnItemContainerStyleChanged(DependencyObject d
, DependencyPropertyChangedEventArgs e
)
61 Selector s
= (Selector
) d
;
62 Style style
= (Style
) e
.NewValue
;
64 int count
= s
.Items
.Count
;
65 for (int i
= 0; i
< count
; i
++)
67 ListBoxItem item
= s
.GetContainerItem (i
);
68 if (item
!= null) // May be null if GetContainerForItemOverride has not been called yet
75 // Set default values for ScrollViewer attached properties
76 ScrollViewer
.SetHorizontalScrollBarVisibility(this, ScrollBarVisibility
.Auto
);
77 ScrollViewer
.SetVerticalScrollBarVisibility(this, ScrollBarVisibility
.Auto
);
84 internal bool IsSelectionActive
{
85 get { return (bool) GetValue (IsSelectionActiveProperty); }
86 set { SetValueImpl (IsSelectionActiveProperty, value); }
89 [Mono
.Xaml
.SetPropertyDelayed
]
90 public int SelectedIndex
{
91 get { return (int)GetValue(SelectedIndexProperty); }
92 set { SetValue (SelectedIndexProperty, value); }
95 public object SelectedItem
{
96 get { return GetValue (SelectedItemProperty); }
97 set { SetValue (SelectedItemProperty, value); }
100 internal ScrollViewer TemplateScrollViewer
{
105 public event SelectionChangedEventHandler SelectionChanged
;
107 void SelectedIndexChanged (DependencyObject o
, DependencyPropertyChangedEventArgs e
)
109 object oldItem
= SelectedItem
;
110 int newVal
= (int) e
.NewValue
;
111 if (newVal
== (int) e
.OldValue
|| Changing
) {
112 SelectedIndex
= newVal
;
119 ClearValue (SelectedItemProperty
);
120 else if (newVal
< Items
.Count
)
121 SelectedItem
= Items
[newVal
];
125 RaiseSelectionChanged (o
, new SelectionChangedEventArgs (oldItem
, SelectedItem
));
128 void SelectedItemChanged (DependencyObject o
, DependencyPropertyChangedEventArgs e
)
130 if (e
.NewValue
== e
.OldValue
|| Changing
) {
131 SelectedItem
= e
.NewValue
;
137 int index
= e
.NewValue
== null ? -1 : Items
.IndexOf (e
.NewValue
);
138 if (index
== -1 && e
.NewValue
!= null) {
139 SelectedIndex
= e
.OldValue
== null ? -1 : Items
.IndexOf (e
.OldValue
);
140 if (e
.OldValue
== null)
141 ClearValue (SelectedItemProperty
);
143 SelectedItem
= e
.OldValue
;
146 SelectedItem
= e
.NewValue
;
147 SelectedIndex
= index
;
148 RaiseSelectionChanged (o
, new SelectionChangedEventArgs (e
.OldValue
, e
.NewValue
));
155 void OnSelectedItemChanged (object oldValue
, object newValue
)
157 if (oldValue
!= null) {
159 if (oldValue
is ListBoxItem
&& IsItemItsOwnContainerOverride (oldValue
))
160 oldItem
= (ListBoxItem
) oldValue
;
162 oldItem
= GetContainerItem (Items
.IndexOf (oldValue
));
165 oldItem
.IsSelected
= false;
168 if (newValue
!= null) {
170 if (newValue
is ListBoxItem
&& IsItemItsOwnContainerOverride (newValue
))
171 newItem
= (ListBoxItem
) newValue
;
173 newItem
= GetContainerItem (Items
.IndexOf (newValue
));
175 if (newItem
!= null) {
176 newItem
.IsSelected
= true;
182 void RaiseSelectionChanged (object o
, SelectionChangedEventArgs e
)
184 object oldVal
= e
.RemovedItems
.Count
== 1 ? e
.RemovedItems
[0] : null;
185 object newVal
= e
.AddedItems
.Count
== 1 ? e
.AddedItems
[0] : null;
186 OnSelectedItemChanged (oldVal
, newVal
);
188 SelectionChangedEventHandler h
= SelectionChanged
;
193 public static bool GetIsSelectionActive (DependencyObject element
)
196 throw new ArgumentNullException ("element");
198 return (bool) element
.GetValue (ListBox
.IsSelectionActiveProperty
);
201 protected override void ClearContainerForItemOverride (DependencyObject element
, object item
)
203 base.ClearContainerForItemOverride (element
, item
);
204 ListBoxItem lbItem
= (ListBoxItem
) element
;
205 lbItem
.Content
= null;
206 lbItem
.IsSelected
= false;
207 lbItem
.ParentSelector
= null;
208 if (SelectedItem
== item
&& GetContainerItem (SelectedIndex
) != null)
212 protected override void PrepareContainerForItemOverride (DependencyObject element
, object item
)
214 base.PrepareContainerForItemOverride (element
, item
);
215 ListBoxItem listBoxItem
= (ListBoxItem
) element
;
216 listBoxItem
.ParentSelector
= this;
217 listBoxItem
.Item
= item
;
218 if (listBoxItem
.IsSelected
&& GetContainerItem (SelectedIndex
) != null)
222 public override void OnApplyTemplate ()
224 base.OnApplyTemplate ();
225 TemplateScrollViewer
= GetTemplateChild("ScrollViewer") as ScrollViewer
;
227 if (TemplateScrollViewer
!= null)
229 TemplateScrollViewer
.TemplatedParentHandlesScrolling
= true;
230 // Update ScrollViewer values
231 TemplateScrollViewer
.HorizontalScrollBarVisibility
= ScrollViewer
.GetHorizontalScrollBarVisibility(this);
232 TemplateScrollViewer
.VerticalScrollBarVisibility
= ScrollViewer
.GetVerticalScrollBarVisibility(this);
236 protected override void OnItemsChanged (System
.Collections
.Specialized
.NotifyCollectionChangedEventArgs e
)
239 case NotifyCollectionChangedAction
.Add
:
240 ListBoxItem item
= e
.NewItems
[0] as ListBoxItem
;
241 if (item
!= null && item
.IsSelected
) {
244 // Ensure we don't fire a SelectionChanged event when we're just updating the index
246 if (e
.NewStartingIndex
<= SelectedIndex
)
251 case NotifyCollectionChangedAction
.Reset
:
255 case NotifyCollectionChangedAction
.Remove
:
256 case NotifyCollectionChangedAction
.Replace
:
258 // Yes this is broken, SelectedItem and SelectedIndex do get out of sync with reality.
261 base.OnItemsChanged (e
);
264 internal virtual void NotifyListItemClicked(ListBoxItem listBoxItem
)
266 if (ModifierKeys
.Control
== (Keyboard
.Modifiers
& ModifierKeys
.Control
)) {
267 if (SelectedItem
== listBoxItem
.Item
)
270 SelectedItem
= listBoxItem
.Item
;
274 internal virtual void NotifyListItemLoaded (ListBoxItem listBoxItem
)
276 if (listBoxItem
.Item
== SelectedItem
) {
277 listBoxItem
.IsSelected
= true;
278 listBoxItem
.Focus ();
282 internal virtual void NotifyListItemGotFocus(ListBoxItem listBoxItemNewFocus
)
287 internal virtual void NotifyListItemLostFocus(ListBoxItem listBoxItemOldFocus
)