@@ -33,6 +33,8 @@ static MultiSelectionComboBox()
3333 {
3434 DefaultStyleKeyProperty . OverrideMetadata ( typeof ( MultiSelectionComboBox ) , new FrameworkPropertyMetadata ( typeof ( MultiSelectionComboBox ) ) ) ;
3535 TextProperty . OverrideMetadata ( typeof ( MultiSelectionComboBox ) , new FrameworkPropertyMetadata ( String . Empty , FrameworkPropertyMetadataOptions . BindsTwoWayByDefault | FrameworkPropertyMetadataOptions . Journal , new PropertyChangedCallback ( OnTextChanged ) ) ) ;
36+ CommandManager . RegisterClassCommandBinding ( typeof ( MultiSelectionComboBox ) , new CommandBinding ( ClearContentCommand , ExecutedClearContentCommand , CanExecuteClearContentCommand ) ) ;
37+ CommandManager . RegisterClassCommandBinding ( typeof ( MultiSelectionComboBox ) , new CommandBinding ( RemoveItemCommand , RemoveItemCommand_Executed , RemoveItemCommand_CanExecute ) ) ;
3638 }
3739
3840 #endregion
@@ -138,40 +140,47 @@ private static bool IsValidSelectionMode(object o)
138140 || value == SelectionMode . Extended ;
139141 }
140142
141- /// <summary>Identifies the <see cref="SelectedItems"/> dependency property.</summary>
142- public static readonly DependencyProperty SelectedItemsProperty =
143- DependencyProperty . Register (
143+
144+ internal static readonly DependencyPropertyKey SelectedItemsPropertyKey =
145+ DependencyProperty . RegisterReadOnly (
144146 nameof ( SelectedItems ) ,
145147 typeof ( IList ) ,
146148 typeof ( MultiSelectionComboBox ) ,
147149 new PropertyMetadata ( ( IList ) null ) ) ;
148150
151+ /// <summary>Identifies the <see cref="SelectedItems"/> dependency property.</summary>
152+ public static readonly DependencyProperty SelectedItemsProperty = SelectedItemsPropertyKey . DependencyProperty ;
153+
154+
149155 /// <summary>
150156 /// The currently selected items.
151157 /// </summary>
152158 [ Bindable ( true ) , Category ( "Appearance" ) , DesignerSerializationVisibility ( DesignerSerializationVisibility . Hidden ) ]
153159 public IList SelectedItems
154160 {
155- get
156- {
157- return PART_PopupListBox ? . SelectedItems ;
158- }
161+ get { return ( IList ) GetValue ( SelectedItemsProperty ) ; }
162+ protected set { SetValue ( SelectedItemsPropertyKey , value ) ; }
159163 }
160164
161- /// <summary>Identifies the <see cref="DisplaySelectedItems"/> dependency property.</summary>
162- public static readonly DependencyProperty DisplaySelectedItemsProperty =
163- DependencyProperty . Register (
165+
166+
167+ internal static readonly DependencyPropertyKey DisplaySelectedItemsPropertyKey =
168+ DependencyProperty . RegisterReadOnly (
164169 nameof ( DisplaySelectedItems ) ,
165170 typeof ( IEnumerable ) ,
166171 typeof ( MultiSelectionComboBox ) ,
167172 new PropertyMetadata ( ( IEnumerable ) null ) ) ;
168173
174+ /// <summary>Identifies the <see cref="DisplaySelectedItems"/> dependency property.</summary>
175+ public static readonly DependencyProperty DisplaySelectedItemsProperty = DisplaySelectedItemsPropertyKey . DependencyProperty ;
176+
169177 /// <summary>
170178 /// Gets the <see cref="SelectedItems"/> in the specified order which was set via <see cref="OrderSelectedItemsBy"/>
171179 /// </summary>
172180 public IEnumerable DisplaySelectedItems
173181 {
174182 get { return ( IEnumerable ) GetValue ( DisplaySelectedItemsProperty ) ; }
183+ protected set { SetValue ( DisplaySelectedItemsPropertyKey , value ) ; }
175184 }
176185
177186 /// <summary>Identifies the <see cref="OrderSelectedItemsBy"/> dependency property.</summary>
@@ -246,20 +255,25 @@ public string Separator
246255 set { SetValue ( SeparatorProperty , value ) ; }
247256 }
248257
249- /// <summary>Identifies the <see cref="HasCustomText"/> dependency property.</summary>
250- public static readonly DependencyProperty HasCustomTextProperty =
251- DependencyProperty . Register (
258+
259+ internal static readonly DependencyPropertyKey HasCustomTextPropertyKey =
260+ DependencyProperty . RegisterReadOnly (
252261 nameof ( HasCustomText ) ,
253262 typeof ( bool ) ,
254263 typeof ( MultiSelectionComboBox ) ,
255264 new PropertyMetadata ( false ) ) ;
256265
266+
267+ /// <summary>Identifies the <see cref="HasCustomText"/> dependency property.</summary>
268+ public static readonly DependencyProperty HasCustomTextProperty = HasCustomTextPropertyKey . DependencyProperty ;
269+
257270 /// <summary>
258271 /// Indicates if the text is userdefined
259272 /// </summary>
260273 public bool HasCustomText
261274 {
262275 get { return ( bool ) GetValue ( HasCustomTextProperty ) ; }
276+ protected set { SetValue ( HasCustomTextPropertyKey , BooleanBoxes . Box ( value ) ) ; }
263277 }
264278
265279 /// <summary>Identifies the <see cref="TextWrapping"/> dependency property.</summary>
@@ -351,8 +365,14 @@ public IParseStringToObject StringToObjectParser
351365 /// </summary>
352366 public void ResetEditableText ( )
353367 {
354- SetCurrentValue ( HasCustomTextProperty , BooleanBoxes . FalseBox ) ;
368+ var oldSelectionStart = PART_EditableTextBox . SelectionStart ;
369+ var oldSelectionLength = PART_EditableTextBox . SelectionLength ;
370+
371+ HasCustomText = false ;
355372 UpdateEditableText ( ) ;
373+
374+ PART_EditableTextBox . SelectionStart = oldSelectionStart ;
375+ PART_EditableTextBox . SelectionLength = oldSelectionLength ;
356376 }
357377
358378 /// <summary>Identifies the <see cref="DisabledPopupOverlayContent"/> dependency property.</summary>
@@ -519,7 +539,9 @@ public int SelectItemsFromTextInputDelay
519539 private void UpdateEditableText ( )
520540 {
521541 if ( PART_EditableTextBox is null || SelectedItems is null )
542+ {
522543 return ;
544+ }
523545
524546 var selectedItemsText = GetSelectedItemsText ( ) ;
525547
@@ -578,19 +600,18 @@ private void UpdateHasCustomText(string selectedItemsText)
578600
579601 bool hasCustomText = ! ( ( string . IsNullOrEmpty ( selectedItemsText ) && string . IsNullOrEmpty ( Text ) ) || string . Equals ( Text , selectedItemsText , EditableTextStringComparision ) ) ;
580602
581- SetCurrentValue ( HasCustomTextProperty , BooleanBoxes . Box ( hasCustomText ) ) ;
603+ HasCustomText = hasCustomText ;
582604 }
583605
584606 private void UpdateDisplaySelectedItems ( OrderSelectedItemsBy orderBy )
585607 {
586- switch ( orderBy )
608+ if ( orderBy == OrderSelectedItemsBy . SelectedOrder )
587609 {
588- case OrderSelectedItemsBy . SelectedOrder :
589- SetCurrentValue ( DisplaySelectedItemsProperty , SelectedItems ) ;
590- break ;
591- case OrderSelectedItemsBy . ItemsSourceOrder :
592- SetCurrentValue ( DisplaySelectedItemsProperty , ( ( IEnumerable < object > ) PART_PopupListBox . SelectedItems ) . OrderBy ( o => Items . IndexOf ( o ) ) ) ;
593- break ;
610+ DisplaySelectedItems = SelectedItems ;
611+ }
612+ else if ( orderBy == OrderSelectedItemsBy . ItemsSourceOrder )
613+ {
614+ DisplaySelectedItems = ( ( IEnumerable < object > ) SelectedItems ) . OrderBy ( o => Items . IndexOf ( o ) ) ;
594615 }
595616 }
596617
@@ -638,7 +659,7 @@ private void UpdateSelectedItemsFromTextTimer_Tick(object sender, EventArgs e)
638659 SelectedItems . Clear ( ) ;
639660 break ;
640661 default :
641- break ;
662+ throw new NotSupportedException ( "Unknown SelectionMode" ) ;
642663 }
643664 return ;
644665 }
@@ -671,7 +692,7 @@ private void UpdateSelectedItemsFromTextTimer_Tick(object sender, EventArgs e)
671692 case SelectionMode . Multiple :
672693 case SelectionMode . Extended :
673694
674- var strings = Text . Split ( new string [ ] { Separator } , StringSplitOptions . RemoveEmptyEntries ) ;
695+ var strings = Text . Split ( new [ ] { Separator } , StringSplitOptions . RemoveEmptyEntries ) ;
675696
676697 SelectedItems . Clear ( ) ;
677698
@@ -698,7 +719,7 @@ private void UpdateSelectedItemsFromTextTimer_Tick(object sender, EventArgs e)
698719 }
699720 break ;
700721 default :
701- break ;
722+ throw new NotSupportedException ( "Unknown SelectionMode" ) ;
702723 }
703724
704725
@@ -752,7 +773,7 @@ private object TryAddObjectFromString(string input)
752773 // Clear Text Command
753774 public static RoutedUICommand ClearContentCommand { get ; } = new RoutedUICommand ( "ClearContent" , nameof ( ClearContentCommand ) , typeof ( MultiSelectionComboBox ) ) ;
754775
755- private void ExecutedClearContentCommand ( object sender , ExecutedRoutedEventArgs e )
776+ private static void ExecutedClearContentCommand ( object sender , ExecutedRoutedEventArgs e )
756777 {
757778 if ( sender is MultiSelectionComboBox multiSelectionCombo )
758779 {
@@ -771,12 +792,14 @@ private void ExecutedClearContentCommand(object sender, ExecutedRoutedEventArgs
771792 case SelectionMode . Extended :
772793 multiSelectionCombo . SelectedItems . Clear ( ) ;
773794 break ;
795+ default :
796+ throw new NotSupportedException ( "Unknown SelectionMode" ) ;
774797 }
775798 }
776799 }
777800 }
778801
779- private void CanExecuteClearContentCommand ( object sender , CanExecuteRoutedEventArgs e )
802+ private static void CanExecuteClearContentCommand ( object sender , CanExecuteRoutedEventArgs e )
780803 {
781804 e . CanExecute = false ;
782805 if ( sender is MultiSelectionComboBox multiSelectionComboBox )
@@ -787,7 +810,7 @@ private void CanExecuteClearContentCommand(object sender, CanExecuteRoutedEventA
787810
788811 public static RoutedUICommand RemoveItemCommand { get ; } = new RoutedUICommand ( "Remove item" , nameof ( RemoveItemCommand ) , typeof ( MultiSelectionComboBox ) ) ;
789812
790- private void RemoveItemCommand_Executed ( object sender , ExecutedRoutedEventArgs e )
813+ private static void RemoveItemCommand_Executed ( object sender , ExecutedRoutedEventArgs e )
791814 {
792815 if ( sender is MultiSelectionComboBox multiSelectionCombo && multiSelectionCombo . SelectedItems . Contains ( e . Parameter ) )
793816 {
@@ -800,7 +823,7 @@ private void RemoveItemCommand_Executed(object sender, ExecutedRoutedEventArgs e
800823 }
801824 }
802825
803- private void RemoveItemCommand_CanExecute ( object sender , CanExecuteRoutedEventArgs e )
826+ private static void RemoveItemCommand_CanExecute ( object sender , CanExecuteRoutedEventArgs e )
804827 {
805828 e . CanExecute = false ;
806829 if ( sender is MultiSelectionComboBox )
@@ -857,15 +880,13 @@ public override void OnApplyTemplate()
857880 {
858881 PART_PopupListBox . SelectionChanged -= PART_PopupListBox_SelectionChanged ;
859882 PART_PopupListBox . SelectionChanged += PART_PopupListBox_SelectionChanged ;
883+ SelectedItems = PART_PopupListBox . SelectedItems ;
860884 }
861885 else
862886 {
863887 throw new MahAppsException ( $ "The template part \" { nameof ( PART_PopupListBox ) } \" could not be found.") ;
864888 }
865889
866- CommandBindings . Add ( new CommandBinding ( ClearContentCommand , ExecutedClearContentCommand , CanExecuteClearContentCommand ) ) ;
867- CommandBindings . Add ( new CommandBinding ( RemoveItemCommand , RemoveItemCommand_Executed , RemoveItemCommand_CanExecute ) ) ;
868-
869890 // Do update the text
870891 UpdateEditableText ( ) ;
871892 UpdateDisplaySelectedItems ( ) ;
@@ -889,7 +910,10 @@ protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
889910 }
890911
891912 // If we have the ItemsSource set, we need to exit here.
892- if ( ReadLocalValue ( ItemsSourceProperty ) != DependencyProperty . UnsetValue ) return ;
913+ if ( ( PART_PopupListBox ? . Items as IList ) ? . IsReadOnly ?? true )
914+ {
915+ return ;
916+ }
893917
894918 switch ( e . Action )
895919 {
@@ -908,11 +932,7 @@ protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
908932 break ;
909933
910934 case NotifyCollectionChangedAction . Replace :
911- // TODO Add Handler
912- break ;
913935 case NotifyCollectionChangedAction . Move :
914- // TODO Add Handler
915- break ;
916936 case NotifyCollectionChangedAction . Reset :
917937 PART_PopupListBox . Items . Clear ( ) ;
918938 foreach ( var item in Items )
@@ -921,7 +941,7 @@ protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
921941 }
922942 break ;
923943 default :
924- break ;
944+ throw new NotSupportedException ( "Unsupported NotifyCollectionChangedAction" ) ;
925945 }
926946 }
927947
@@ -951,10 +971,16 @@ protected override void OnDropDownOpened(EventArgs e)
951971
952972 PART_PopupListBox . Focus ( ) ;
953973
954- if ( PART_PopupListBox . Items . Count == 0 ) return ;
974+ if ( PART_PopupListBox . Items . Count == 0 )
975+ {
976+ return ;
977+ }
955978
956979 var index = PART_PopupListBox . SelectedIndex ;
957- if ( index < 0 ) index = 0 ;
980+ if ( index < 0 )
981+ {
982+ index = 0 ;
983+ }
958984
959985 Action action = ( ) =>
960986 {
@@ -1052,7 +1078,10 @@ private void MultiSelectionComboBox_Loaded(object sender, EventArgs e)
10521078 Loaded -= MultiSelectionComboBox_Loaded ;
10531079
10541080 // If we have the ItemsSource set, we need to exit here.
1055- if ( ReadLocalValue ( ItemsSourceProperty ) != DependencyProperty . UnsetValue ) return ;
1081+ if ( ( PART_PopupListBox ? . Items as IList ) ? . IsReadOnly ?? true )
1082+ {
1083+ return ;
1084+ }
10561085
10571086 PART_PopupListBox . Items . Clear ( ) ;
10581087 foreach ( var item in Items )
0 commit comments