All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1046 lines
31 KiB

/*************************************************************************************
Toolkit for WPF
Copyright (C) 2007-2025 Xceed Software Inc.
This program is provided to you under the terms of the XCEED SOFTWARE, INC.
COMMUNITY LICENSE AGREEMENT (for non-commercial use) as published at
https://github.com/xceedsoftware/wpftoolkit/blob/master/license.md
For more features, controls, and fast professional support,
pick up the Plus Edition at https://xceed.com/xceed-toolkit-plus-for-wpf/
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
***********************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Xceed.Wpf.Toolkit.Core.Utilities;
using Xceed.Wpf.Toolkit.PropertyGrid;
using Xceed.Wpf.Toolkit.PropertyGrid.Editors;
namespace Xceed.Wpf.Toolkit.Primitives
{
public class Selector : ItemsControl, IWeakEventListener //should probably make this control an ICommandSource
{
#region Members
private bool _surpressItemSelectionChanged;
private bool _ignoreSelectedItemChanged;
private bool _ignoreSelectedValueChanged;
private int _ignoreSelectedItemsCollectionChanged;
private int _ignoreSelectedMemberPathValuesChanged;
private IList _selectedItems;
private IList _removedItems = new ObservableCollection<object>();
private object[] _internalSelectedItems;
private ValueChangeHelper _selectedMemberPathValuesHelper;
private ValueChangeHelper _valueMemberPathValuesHelper;
#endregion //Members
#region Constructors
public Selector()
{
this.SelectedItems = new ObservableCollection<object>();
AddHandler( Selector.SelectedEvent, new RoutedEventHandler( ( s, args ) => this.OnItemSelectionChangedCore( args, false ) ) );
AddHandler( Selector.UnSelectedEvent, new RoutedEventHandler( ( s, args ) => this.OnItemSelectionChangedCore( args, true ) ) );
_selectedMemberPathValuesHelper = new ValueChangeHelper( this.OnSelectedMemberPathValuesChanged );
_valueMemberPathValuesHelper = new ValueChangeHelper( this.OnValueMemberPathValuesChanged );
}
#endregion //Constructors
#region Properties
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command", typeof( ICommand ), typeof( Selector ), new PropertyMetadata( ( ICommand )null ) );
[TypeConverter( typeof( CommandConverter ) )]
public ICommand Command
{
get
{
return ( ICommand )GetValue( CommandProperty );
}
set
{
SetValue( CommandProperty, value );
}
}
#region Delimiter
public static readonly DependencyProperty DelimiterProperty = DependencyProperty.Register( "Delimiter", typeof( string ), typeof( Selector ), new UIPropertyMetadata( ",", OnDelimiterChanged ) );
public string Delimiter
{
get
{
return ( string )GetValue( DelimiterProperty );
}
set
{
SetValue( DelimiterProperty, value );
}
}
private static void OnDelimiterChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
{
( ( Selector )o ).OnSelectedItemChanged( ( string )e.OldValue, ( string )e.NewValue );
}
protected virtual void OnSelectedItemChanged( string oldValue, string newValue )
{
if( !this.IsInitialized )
return;
this.UpdateSelectedValue();
}
#endregion
#region SelectedItem property
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( "SelectedItem", typeof( object ), typeof( Selector ), new UIPropertyMetadata( null, OnSelectedItemChanged ) );
public object SelectedItem
{
get
{
return ( object )GetValue( SelectedItemProperty );
}
set
{
SetValue( SelectedItemProperty, value );
}
}
private static void OnSelectedItemChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args )
{
( ( Selector )sender ).OnSelectedItemChanged( args.OldValue, args.NewValue );
}
protected virtual void OnSelectedItemChanged( object oldValue, object newValue )
{
if( !this.IsInitialized || _ignoreSelectedItemChanged )
return;
_ignoreSelectedItemsCollectionChanged++;
this.SelectedItems.Clear();
if( newValue != null )
{
this.SelectedItems.Add( newValue );
}
this.UpdateFromSelectedItems();
_ignoreSelectedItemsCollectionChanged--;
}
#endregion
#region SelectedItems Property
public IList SelectedItems
{
get
{
return _selectedItems;
}
private set
{
if( value == null )
throw new ArgumentNullException( "value" );
INotifyCollectionChanged oldCollection = _selectedItems as INotifyCollectionChanged;
INotifyCollectionChanged newCollection = value as INotifyCollectionChanged;
if( oldCollection != null )
{
CollectionChangedEventManager.RemoveListener( oldCollection, this );
}
if( newCollection != null )
{
CollectionChangedEventManager.AddListener( newCollection, this );
}
var newValue = value;
var oldValue = _selectedItems;
if( oldValue != null )
{
foreach( var item in oldValue )
{
if( ( ( newValue != null ) && !newValue.Contains( item ) ) || ( newValue == null ) )
{
this.OnItemSelectionChanged( new ItemSelectionChangedEventArgs( Selector.ItemSelectionChangedEvent, this, item, false ) );
if( Command != null )
{
this.Command.Execute( item );
}
}
}
}
if( newValue != null )
{
foreach( var item in newValue )
{
this.OnItemSelectionChanged( new ItemSelectionChangedEventArgs( Selector.ItemSelectionChangedEvent, this, item, true ) );
if( ( ( oldValue != null ) && !oldValue.Contains( item ) ) || ( oldValue == null ) )
{
if( Command != null )
{
this.Command.Execute( item );
}
}
}
}
_selectedItems = value;
}
}
#endregion SelectedItems
#region SelectedItemsOverride property
public static readonly DependencyProperty SelectedItemsOverrideProperty = DependencyProperty.Register( "SelectedItemsOverride", typeof( IList ), typeof( Selector ), new UIPropertyMetadata( null, SelectedItemsOverrideChanged ) );
public IList SelectedItemsOverride
{
get
{
return ( IList )GetValue( SelectedItemsOverrideProperty );
}
set
{
SetValue( SelectedItemsOverrideProperty, value );
}
}
private static void SelectedItemsOverrideChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args )
{
( ( Selector )sender ).OnSelectedItemsOverrideChanged( ( IList )args.OldValue, ( IList )args.NewValue );
}
protected virtual void OnSelectedItemsOverrideChanged( IList oldValue, IList newValue )
{
if( !this.IsInitialized )
return;
this.SelectedItems = ( newValue != null ) ? newValue : new ObservableCollection<object>();
this.UpdateFromSelectedItems();
}
#endregion
#region SelectedMemberPath Property
public static readonly DependencyProperty SelectedMemberPathProperty = DependencyProperty.Register( "SelectedMemberPath", typeof( string ), typeof( Selector ), new UIPropertyMetadata( null, OnSelectedMemberPathChanged ) );
public string SelectedMemberPath
{
get
{
return ( string )GetValue( SelectedMemberPathProperty );
}
set
{
SetValue( SelectedMemberPathProperty, value );
}
}
private static void OnSelectedMemberPathChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
{
Selector sel = ( ( Selector )o );
sel.OnSelectedMemberPathChanged( ( string )e.OldValue, ( string )e.NewValue );
}
protected virtual void OnSelectedMemberPathChanged( string oldValue, string newValue )
{
if( !this.IsInitialized )
return;
this.UpdateSelectedMemberPathValuesBindings();
}
#endregion //SelectedMemberPath
#region SelectedValue
public static readonly DependencyProperty SelectedValueProperty = DependencyProperty.Register( "SelectedValue", typeof( string ), typeof( Selector ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedValueChanged ) );
public string SelectedValue
{
get
{
return ( string )GetValue( SelectedValueProperty );
}
set
{
SetValue( SelectedValueProperty, value );
}
}
private static void OnSelectedValueChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
{
Selector selector = o as Selector;
if( selector != null )
selector.OnSelectedValueChanged( ( string )e.OldValue, ( string )e.NewValue );
}
protected virtual void OnSelectedValueChanged( string oldValue, string newValue )
{
if( !( this is PropertyGridEditorEnumCheckComboBox ) )
{
if( !this.IsInitialized || _ignoreSelectedValueChanged )
return;
}
UpdateFromSelectedValue();
}
#endregion //SelectedValue
#region ValueMemberPath
public static readonly DependencyProperty ValueMemberPathProperty = DependencyProperty.Register( "ValueMemberPath", typeof( string ), typeof( Selector ), new UIPropertyMetadata( OnValueMemberPathChanged ) );
public string ValueMemberPath
{
get
{
return ( string )GetValue( ValueMemberPathProperty );
}
set
{
SetValue( ValueMemberPathProperty, value );
}
}
private static void OnValueMemberPathChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
{
Selector sel = ( ( Selector )o );
sel.OnValueMemberPathChanged( ( string )e.OldValue, ( string )e.NewValue );
}
protected virtual void OnValueMemberPathChanged( string oldValue, string newValue )
{
if( !this.IsInitialized )
return;
this.UpdateValueMemberPathValuesBindings();
}
#endregion
#region ItemsCollection Property
protected IEnumerable ItemsCollection
{
get
{
return ItemsSource ?? ( ( IEnumerable )Items ?? ( IEnumerable )new object[ 0 ] );
}
}
#endregion
#endregion //Properties
#region Base Class Overrides
protected override bool IsItemItsOwnContainerOverride( object item )
{
return item is SelectorItem;
}
protected override DependencyObject GetContainerForItemOverride()
{
return new SelectorItem();
}
protected override void PrepareContainerForItemOverride( DependencyObject element, object item )
{
base.PrepareContainerForItemOverride( element, item );
_surpressItemSelectionChanged = true;
var selectorItem = element as FrameworkElement;
selectorItem.SetValue( SelectorItem.IsSelectedProperty, SelectedItems.Contains( item ) );
_surpressItemSelectionChanged = false;
}
protected override void OnItemsSourceChanged( IEnumerable oldValue, IEnumerable newValue )
{
base.OnItemsSourceChanged( oldValue, newValue );
var oldCollection = oldValue as INotifyCollectionChanged;
var newCollection = newValue as INotifyCollectionChanged;
if( oldCollection != null )
{
CollectionChangedEventManager.RemoveListener( oldCollection, this );
}
if( newCollection != null )
{
CollectionChangedEventManager.AddListener( newCollection, this );
}
if( !this.IsInitialized )
return;
if( this.SelectedItemsOverride == null )
{
if( !VirtualizingStackPanel.GetIsVirtualizing( this )
|| ( VirtualizingStackPanel.GetIsVirtualizing( this ) && ( newValue != null ) ) )
{
this.RemoveUnavailableSelectedItems();
}
}
this.UpdateSelectedMemberPathValuesBindings();
this.UpdateValueMemberPathValuesBindings();
}
protected override void OnItemsChanged( NotifyCollectionChangedEventArgs e )
{
base.OnItemsChanged( e );
if( this.ItemsSource == null )
{
this.RemoveUnavailableSelectedItems();
}
}
// When a DataTemplate includes a CheckComboBox, some bindings are
// not working, like SelectedValue.
// We use a priority system to select the good items after initialization.
public override void EndInit()
{
base.EndInit();
if( this.SelectedItemsOverride != null )
{
this.OnSelectedItemsOverrideChanged( null, this.SelectedItemsOverride );
}
else if( this.SelectedMemberPath != null )
{
this.OnSelectedMemberPathChanged( null, this.SelectedMemberPath );
}
else if( this.SelectedValue != null )
{
this.OnSelectedValueChanged( null, this.SelectedValue );
}
else if( this.SelectedItem != null )
{
this.OnSelectedItemChanged( null, this.SelectedItem );
}
if( this.ValueMemberPath != null )
{
this.OnValueMemberPathChanged( null, this.ValueMemberPath );
}
}
#endregion //Base Class Overrides
#region Events
public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent( "SelectedEvent", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( Selector ) );
public static readonly RoutedEvent UnSelectedEvent = EventManager.RegisterRoutedEvent( "UnSelectedEvent", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( Selector ) );
public static readonly RoutedEvent ItemSelectionChangedEvent = EventManager.RegisterRoutedEvent( "ItemSelectionChanged", RoutingStrategy.Bubble, typeof( ItemSelectionChangedEventHandler ), typeof( Selector ) );
public event ItemSelectionChangedEventHandler ItemSelectionChanged
{
add
{
AddHandler( ItemSelectionChangedEvent, value );
}
remove
{
RemoveHandler( ItemSelectionChangedEvent, value );
}
}
#endregion //Events
#region Methods
protected object GetPathValue( object item, string propertyPath )
{
if( item == null )
throw new ArgumentNullException( "item" );
if( String.IsNullOrEmpty( propertyPath )
|| propertyPath == "." )
return item;
if( propertyPath.Contains( "." ) )
{
object objectValue = item;
var parts = propertyPath.Split( new char[] { '.' } );
foreach( var part in parts )
{
var prop = objectValue.GetType().GetProperty( part );
if( prop != null )
{
objectValue = prop.GetValue( objectValue, null );
}
else
{
return null;
}
}
return objectValue;
}
else
{
var prop = item.GetType().GetProperty( propertyPath );
return ( prop != null )
? prop.GetValue( item, null )
: null;
}
}
protected object GetItemValue( object item )
{
return ( item != null )
? this.GetPathValue( item, this.ValueMemberPath )
: null;
}
protected object ResolveItemByValue( string value )
{
if( !String.IsNullOrEmpty( ValueMemberPath ) )
{
foreach( object item in ItemsCollection )
{
var property = item.GetType().GetProperty( ValueMemberPath );
if( property != null )
{
var propertyValue = property.GetValue( item, null );
if( value.Equals( propertyValue.ToString(), StringComparison.InvariantCultureIgnoreCase ) )
return item;
}
}
}
return value;
}
internal void UpdateFromList( List<string> selectedValues, Func<object, object> GetItemfunction )
{
_ignoreSelectedItemsCollectionChanged++;
// Just update the SelectedItems collection content
// and let the synchronization be made from UpdateFromSelectedItems();
SelectedItems.Clear();
if( ( selectedValues != null ) && ( selectedValues.Count > 0 ) )
{
ValueEqualityComparer comparer = new ValueEqualityComparer();
foreach( object item in ItemsCollection )
{
object itemValue = GetItemfunction( item );
bool isSelected = ( itemValue != null )
&& selectedValues.Contains( itemValue.ToString(), comparer );
if( isSelected )
{
SelectedItems.Add( item );
}
}
}
_ignoreSelectedItemsCollectionChanged--;
this.UpdateFromSelectedItems();
}
internal void UpdateSelectedItemsWithoutNotifications( List<object> selectedValues )
{
_ignoreSelectedItemsCollectionChanged++;
// Just update the SelectedItems collection content
// and let the synchronization be made from UpdateFromSelectedItems();
this.SelectedItems.Clear();
if( ( selectedValues != null ) && ( selectedValues.Count > 0 ) )
{
foreach( object item in this.ItemsCollection )
{
this.SelectedItems.Add( item );
}
}
_ignoreSelectedItemsCollectionChanged--;
this.UpdateFromSelectedItems();
}
private bool? GetSelectedMemberPathValue( object item )
{
if( String.IsNullOrEmpty( this.SelectedMemberPath ) )
return null;
if( item == null )
return null;
string[] nameParts = this.SelectedMemberPath.Split( '.' );
if( nameParts.Length == 1 )
{
var property = item.GetType().GetProperty( this.SelectedMemberPath );
if( ( property != null ) && ( property.PropertyType == typeof( bool ) ) )
return property.GetValue( item, null ) as bool?;
return null;
}
for( int i = 0; i < nameParts.Count(); ++i )
{
var type = item.GetType();
var info = type.GetProperty( nameParts[ i ] );
if( info == null )
{
return null;
}
if( i == nameParts.Count() - 1 )
{
if( info.PropertyType == typeof( bool ) )
return info.GetValue( item, null ) as bool?;
}
else
{
item = info.GetValue( item, null );
}
}
return null;
}
private void SetSelectedMemberPathValue( object item, bool value )
{
if( String.IsNullOrEmpty( this.SelectedMemberPath ) )
return;
if( item == null )
return;
string[] nameParts = this.SelectedMemberPath.Split( '.' );
if( nameParts.Length == 1 )
{
var property = item.GetType().GetProperty( this.SelectedMemberPath );
if( ( property != null ) && ( property.PropertyType == typeof( bool ) ) && ( ( bool )property.GetValue( item, null ) != value ) )
{
property.SetValue( item, value, null );
}
return;
}
for( int i = 0; i < nameParts.Count(); ++i )
{
var type = item.GetType();
var info = type.GetProperty( nameParts[ i ] );
if( info == null )
return;
if( i == nameParts.Count() - 1 )
{
if( info.PropertyType == typeof( bool ) )
{
info.SetValue( item, value, null );
}
}
else
{
item = info.GetValue( item, null );
}
}
}
protected virtual void OnSelectedItemsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
{
if( _ignoreSelectedItemsCollectionChanged > 0 )
return;
// Keep it simple for now. Just update all
this.UpdateFromSelectedItems();
if( e.Action == NotifyCollectionChangedAction.Reset )
{
if( _internalSelectedItems != null )
{
foreach( var item in _internalSelectedItems )
{
this.OnItemSelectionChanged( new ItemSelectionChangedEventArgs( Selector.ItemSelectionChangedEvent, this, item, false ) );
if( Command != null )
{
this.Command.Execute( item );
}
}
}
}
if( e.OldItems != null )
{
foreach( var item in e.OldItems )
{
this.OnItemSelectionChanged( new ItemSelectionChangedEventArgs( Selector.ItemSelectionChangedEvent, this, item, false ) );
if( Command != null )
{
this.Command.Execute( item );
}
}
}
if( e.NewItems != null )
{
foreach( var item in e.NewItems )
{
this.OnItemSelectionChanged( new ItemSelectionChangedEventArgs( Selector.ItemSelectionChangedEvent, this, item, true ) );
if( Command != null )
{
this.Command.Execute( item );
}
}
}
}
private void OnItemSelectionChangedCore( RoutedEventArgs args, bool unselected )
{
object item = this.ItemContainerGenerator.ItemFromContainer( ( DependencyObject )args.OriginalSource );
// When the item is it's own container, "UnsetValue" will be returned.
if( item == DependencyProperty.UnsetValue )
{
item = args.OriginalSource;
}
var itemselectionChangingArgs = new ItemSelectionChangingEventArgs( item, !unselected );
this.OnItemSelectionChanging( itemselectionChangingArgs );
if( itemselectionChangingArgs.Cancel )
{
this.UpdateSelectorItem( item, unselected, false );
return;
}
if( unselected )
{
while( SelectedItems.Contains( item ) )
SelectedItems.Remove( item );
}
else
{
if( !SelectedItems.Contains( item ) )
SelectedItems.Add( item );
}
}
private void OnItemsSourceCollectionChanged( object sender, NotifyCollectionChangedEventArgs args )
{
this.RemoveUnavailableSelectedItems();
this.AddAvailableRemovedItems();
this.UpdateSelectedMemberPathValuesBindings();
this.UpdateValueMemberPathValuesBindings();
}
private void OnSelectedMemberPathValuesChanged()
{
if( _ignoreSelectedMemberPathValuesChanged > 0 )
return;
this.UpdateFromSelectedMemberPathValues();
}
private void OnValueMemberPathValuesChanged()
{
this.UpdateSelectedValue();
}
private void UpdateSelectedMemberPathValuesBindings()
{
_selectedMemberPathValuesHelper.UpdateValueSource( ItemsCollection, SelectedMemberPath );
this.UpdateFromSelectedMemberPathValues();
}
private void UpdateValueMemberPathValuesBindings()
{
_valueMemberPathValuesHelper.UpdateValueSource( ItemsCollection, ValueMemberPath );
}
protected virtual void OnItemSelectionChanged( ItemSelectionChangedEventArgs args )
{
if( _surpressItemSelectionChanged )
return;
RaiseEvent( args );
}
public event EventHandler<ItemSelectionChangingEventArgs> ItemSelectionChanging;
protected virtual void OnItemSelectionChanging( ItemSelectionChangingEventArgs args )
{
if( ItemSelectionChanging != null )
{
ItemSelectionChanging( this, args );
}
}
private void UpdateSelectedValue()
{
#if VS2008
string newValue = String.Join( Delimiter, SelectedItems.Cast<object>().Select( x => GetItemValue( x ).ToString() ).ToArray() );
#else
string newValue = String.Join( Delimiter, SelectedItems.Cast<object>().Select( x => GetItemValue( x ) ) );
#endif
if( String.IsNullOrEmpty( SelectedValue ) || !SelectedValue.Equals( newValue ) )
{
_ignoreSelectedValueChanged = true;
SelectedValue = newValue;
_ignoreSelectedValueChanged = false;
}
}
private void UpdateSelectedItem()
{
if( !SelectedItems.Contains( SelectedItem ) )
{
_ignoreSelectedItemChanged = true;
SelectedItem = ( SelectedItems.Count > 0 ) ? SelectedItems[ 0 ] : null;
_ignoreSelectedItemChanged = false;
}
}
private void UpdateFromSelectedMemberPathValues()
{
_ignoreSelectedItemsCollectionChanged++;
foreach( var item in this.ItemsCollection )
{
var isSelected = this.GetSelectedMemberPathValue( item );
if( isSelected != null )
{
if( isSelected.Value )
{
if( !this.SelectedItems.Contains( item ) )
{
this.SelectedItems.Add( item );
}
}
else
{
if( this.SelectedItems.Contains( item ) )
{
this.SelectedItems.Remove( item );
}
}
this.UpdateSelectorItem( item, isSelected.Value );
}
}
_ignoreSelectedItemsCollectionChanged--;
this.UpdateSelectedItem();
this.UpdateSelectedValue();
this.UpdateInternalSelectedItems();
}
internal void UpdateSelectedItems( IList selectedItems )
{
if( selectedItems == null )
throw new ArgumentNullException( "selectedItems" );
// Just check if the collection is the same..
if( selectedItems.Count == this.SelectedItems.Count
&& selectedItems.Cast<object>().SequenceEqual( this.SelectedItems.Cast<object>() ) )
return;
_ignoreSelectedItemsCollectionChanged++;
this.SelectedItems.Clear();
foreach( object newItem in selectedItems )
{
this.SelectedItems.Add( newItem );
}
_ignoreSelectedItemsCollectionChanged--;
this.UpdateFromSelectedItems();
}
private void UpdateFromSelectedItems()
{
foreach( var o in this.ItemsCollection )
{
bool isSelected = this.SelectedItems.Contains( o );
_ignoreSelectedMemberPathValuesChanged++;
this.SetSelectedMemberPathValue( o, isSelected );
_ignoreSelectedMemberPathValuesChanged--;
this.UpdateSelectorItem( o, isSelected );
}
this.UpdateSelectedItem();
this.UpdateSelectedValue();
this.UpdateInternalSelectedItems();
}
private void UpdateInternalSelectedItems()
{
_internalSelectedItems = new object[ this.SelectedItems.Count ];
this.SelectedItems.CopyTo( _internalSelectedItems, 0 );
}
private void UpdateSelectorItem( object item, bool isSelected, bool raiseSelectionChangedEvent = true )
{
var selectorItem = ItemContainerGenerator.ContainerFromItem( item ) as SelectorItem;
if( selectorItem != null )
{
selectorItem.SetIsSelected( isSelected, raiseSelectionChangedEvent );
}
}
private void RemoveUnavailableSelectedItems()
{
_ignoreSelectedItemsCollectionChanged++;
HashSet<object> hash = new HashSet<object>( ItemsCollection.Cast<object>() );
for( int i = 0; i < SelectedItems.Count; i++ )
{
if( !hash.Contains( SelectedItems[ i ] ) )
{
_removedItems.Add( SelectedItems[ i ] );
SelectedItems.RemoveAt( i );
i--;
}
}
_ignoreSelectedItemsCollectionChanged--;
UpdateSelectedItem();
UpdateSelectedValue();
}
private void AddAvailableRemovedItems()
{
HashSet<object> hash = new HashSet<object>( ItemsCollection.Cast<object>() );
for( int i = 0; i < _removedItems.Count; i++ )
{
if( hash.Contains( _removedItems[ i ] ) )
{
SelectedItems.Add( _removedItems[ i ] );
_removedItems.RemoveAt( i );
i--;
}
}
}
private void UpdateFromSelectedValue()
{
List<string> selectedValues = null;
if( !String.IsNullOrEmpty( SelectedValue ) )
{
selectedValues = SelectedValue.Split( new string[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries ).ToList();
}
this.UpdateFromList( selectedValues, this.GetItemValue );
}
#endregion //Methods
#region IWeakEventListener Members
public bool ReceiveWeakEvent( Type managerType, object sender, EventArgs e )
{
if( managerType == typeof( CollectionChangedEventManager ) )
{
if( object.ReferenceEquals( _selectedItems, sender ) )
{
this.OnSelectedItemsCollectionChanged( sender, ( NotifyCollectionChangedEventArgs )e );
return true;
}
else if( object.ReferenceEquals( ItemsCollection, sender ) )
{
this.OnItemsSourceCollectionChanged( sender, ( NotifyCollectionChangedEventArgs )e );
return true;
}
}
return false;
}
#endregion
#region ValueEqualityComparer private class
private class ValueEqualityComparer : IEqualityComparer<string>
{
public bool Equals( string x, string y )
{
return string.Equals( x, y, StringComparison.InvariantCultureIgnoreCase );
}
public int GetHashCode( string obj )
{
return 1;
}
}
#endregion
}
public delegate void ItemSelectionChangedEventHandler( object sender, ItemSelectionChangedEventArgs e );
public class ItemSelectionChangedEventArgs : RoutedEventArgs
{
public bool IsSelected
{
get;
private set;
}
public object Item
{
get;
private set;
}
public ItemSelectionChangedEventArgs( RoutedEvent routedEvent, object source, object item, bool isSelected )
: base( routedEvent, source )
{
Item = item;
IsSelected = isSelected;
}
}
public delegate void ItemSelectionChangingEventHandler( object sender, ItemSelectionChangingEventArgs e );
public class ItemSelectionChangingEventArgs : CancelEventArgs
{
public bool NewIsSelected
{
get;
private set;
}
public object Item
{
get;
private set;
}
public ItemSelectionChangingEventArgs( object item, bool isSelected )
: base()
{
this.Item = item;
this.NewIsSelected = isSelected;
}
}
}