Init
This commit is contained in:
@@ -0,0 +1,598 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
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.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Xceed.Wpf.Toolkit.Core.Utilities;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit
|
||||
{
|
||||
[TemplatePart( Name = PART_NewItemTypesComboBox, Type = typeof( ComboBox ) )]
|
||||
[TemplatePart( Name = PART_PropertyGrid, Type = typeof( PropertyGrid.PropertyGrid ) )]
|
||||
[TemplatePart( Name = PART_ListBox, Type = typeof( ListBox ) )]
|
||||
public class CollectionControl : Control
|
||||
{
|
||||
private const string PART_NewItemTypesComboBox = "PART_NewItemTypesComboBox";
|
||||
private const string PART_PropertyGrid = "PART_PropertyGrid";
|
||||
private const string PART_ListBox = "PART_ListBox";
|
||||
|
||||
#region Private Members
|
||||
|
||||
private ComboBox _newItemTypesComboBox;
|
||||
private PropertyGrid.PropertyGrid _propertyGrid;
|
||||
private ListBox _listBox;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
#region IsReadOnly Property
|
||||
|
||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register( "IsReadOnly", typeof( bool ), typeof( CollectionControl ), new UIPropertyMetadata( false ) );
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( bool )GetValue( IsReadOnlyProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( IsReadOnlyProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //Items
|
||||
|
||||
#region Items Property
|
||||
|
||||
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register( "Items", typeof( ObservableCollection<object> ), typeof( CollectionControl ), new UIPropertyMetadata( null ) );
|
||||
public ObservableCollection<object> Items
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( ObservableCollection<object> )GetValue( ItemsProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //Items
|
||||
|
||||
#region ItemsSource Property
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( "ItemsSource", typeof( IEnumerable ), typeof( CollectionControl ), new UIPropertyMetadata( null, OnItemsSourceChanged ) );
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return (IEnumerable)GetValue( ItemsSourceProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnItemsSourceChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
var CollectionControl = ( CollectionControl )d;
|
||||
if( CollectionControl != null )
|
||||
CollectionControl.OnItemSourceChanged( (IEnumerable)e.OldValue, (IEnumerable)e.NewValue );
|
||||
}
|
||||
|
||||
public void OnItemSourceChanged( IEnumerable oldValue, IEnumerable newValue )
|
||||
{
|
||||
if( newValue != null )
|
||||
{
|
||||
var dict = newValue as IDictionary;
|
||||
if( dict != null )
|
||||
{
|
||||
// A Dictionary contains KeyValuePair that can't be edited.
|
||||
// We need to Add EditableKeyValuePairs from DictionaryEntries.
|
||||
foreach( DictionaryEntry item in dict )
|
||||
{
|
||||
var keyType = (item.Key != null)
|
||||
? item.Key.GetType()
|
||||
: (dict.GetType().GetGenericArguments().Count() > 0) ? dict.GetType().GetGenericArguments()[0] : typeof( object );
|
||||
var valueType = (item.Value != null)
|
||||
? item.Value.GetType()
|
||||
: (dict.GetType().GetGenericArguments().Count() > 1) ? dict.GetType().GetGenericArguments()[ 1 ] : typeof( object );
|
||||
var editableKeyValuePair = ListUtilities.CreateEditableKeyValuePair( item.Key
|
||||
, keyType
|
||||
, item.Value
|
||||
, valueType );
|
||||
this.Items.Add( editableKeyValuePair );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( var item in newValue )
|
||||
{
|
||||
if( item != null )
|
||||
{
|
||||
Items.Add( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemsSource
|
||||
|
||||
#region ItemsSourceType Property
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceTypeProperty = DependencyProperty.Register( "ItemsSourceType", typeof( Type ), typeof( CollectionControl ), new UIPropertyMetadata( null ) );
|
||||
public Type ItemsSourceType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( Type )GetValue( ItemsSourceTypeProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceTypeProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemsSourceType
|
||||
|
||||
#region NewItemType Property
|
||||
|
||||
public static readonly DependencyProperty NewItemTypesProperty = DependencyProperty.Register( "NewItemTypes", typeof( IList ), typeof( CollectionControl ), new UIPropertyMetadata( null ) );
|
||||
public IList<Type> NewItemTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( IList<Type> )GetValue( NewItemTypesProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( NewItemTypesProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //NewItemType
|
||||
|
||||
#region SelectedItem Property
|
||||
|
||||
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( "SelectedItem", typeof( object ), typeof( CollectionControl ), new UIPropertyMetadata( null ) );
|
||||
public object SelectedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( object )GetValue( SelectedItemProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( SelectedItemProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //SelectedItem
|
||||
|
||||
#endregion //Properties
|
||||
|
||||
#region Override Methods
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if( _newItemTypesComboBox != null )
|
||||
{
|
||||
_newItemTypesComboBox.Loaded -= new RoutedEventHandler( this.NewItemTypesComboBox_Loaded );
|
||||
}
|
||||
_newItemTypesComboBox = GetTemplateChild( PART_NewItemTypesComboBox ) as ComboBox;
|
||||
if( _newItemTypesComboBox != null )
|
||||
{
|
||||
_newItemTypesComboBox.Loaded += new RoutedEventHandler( this.NewItemTypesComboBox_Loaded );
|
||||
}
|
||||
|
||||
_listBox = this.GetTemplateChild( PART_ListBox ) as ListBox;
|
||||
|
||||
if( _propertyGrid != null )
|
||||
{
|
||||
_propertyGrid.PropertyValueChanged -= this.PropertyGrid_PropertyValueChanged;
|
||||
}
|
||||
_propertyGrid = GetTemplateChild( PART_PropertyGrid ) as PropertyGrid.PropertyGrid;
|
||||
if( _propertyGrid != null )
|
||||
{
|
||||
_propertyGrid.PropertyValueChanged += this.PropertyGrid_PropertyValueChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyGrid.PropertyGrid PropertyGrid
|
||||
{
|
||||
get
|
||||
{
|
||||
if( _propertyGrid == null )
|
||||
{
|
||||
this.ApplyTemplate();
|
||||
}
|
||||
return _propertyGrid;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static CollectionControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata( typeof( CollectionControl ), new FrameworkPropertyMetadata( typeof( CollectionControl ) ) );
|
||||
}
|
||||
|
||||
public CollectionControl()
|
||||
{
|
||||
Items = new ObservableCollection<object>();
|
||||
CommandBindings.Add( new CommandBinding( ApplicationCommands.New, AddNew, CanAddNew ) );
|
||||
CommandBindings.Add( new CommandBinding( ApplicationCommands.Delete, Delete, CanDelete ) );
|
||||
CommandBindings.Add( new CommandBinding( ComponentCommands.MoveDown, MoveDown, CanMoveDown ) );
|
||||
CommandBindings.Add( new CommandBinding( ComponentCommands.MoveUp, MoveUp, CanMoveUp ) );
|
||||
}
|
||||
|
||||
#endregion //Constructors
|
||||
|
||||
#region Events
|
||||
|
||||
#region ItemDeleting Event
|
||||
|
||||
public delegate void ItemDeletingRoutedEventHandler( object sender, ItemDeletingEventArgs e );
|
||||
|
||||
public static readonly RoutedEvent ItemDeletingEvent = EventManager.RegisterRoutedEvent( "ItemDeleting", RoutingStrategy.Bubble, typeof( ItemDeletingRoutedEventHandler ), typeof( CollectionControl ) );
|
||||
public event ItemDeletingRoutedEventHandler ItemDeleting
|
||||
{
|
||||
add
|
||||
{
|
||||
AddHandler( ItemDeletingEvent, value );
|
||||
}
|
||||
remove
|
||||
{
|
||||
RemoveHandler( ItemDeletingEvent, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemDeleting Event
|
||||
|
||||
#region ItemDeleted Event
|
||||
|
||||
public delegate void ItemDeletedRoutedEventHandler( object sender, ItemEventArgs e );
|
||||
|
||||
public static readonly RoutedEvent ItemDeletedEvent = EventManager.RegisterRoutedEvent( "ItemDeleted", RoutingStrategy.Bubble, typeof( ItemDeletedRoutedEventHandler ), typeof( CollectionControl ) );
|
||||
public event ItemDeletedRoutedEventHandler ItemDeleted
|
||||
{
|
||||
add
|
||||
{
|
||||
AddHandler( ItemDeletedEvent, value );
|
||||
}
|
||||
remove
|
||||
{
|
||||
RemoveHandler( ItemDeletedEvent, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemDeleted Event
|
||||
|
||||
#region ItemAdding Event
|
||||
|
||||
public delegate void ItemAddingRoutedEventHandler( object sender, ItemAddingEventArgs e );
|
||||
|
||||
public static readonly RoutedEvent ItemAddingEvent = EventManager.RegisterRoutedEvent( "ItemAdding", RoutingStrategy.Bubble, typeof( ItemAddingRoutedEventHandler ), typeof( CollectionControl ) );
|
||||
public event ItemAddingRoutedEventHandler ItemAdding
|
||||
{
|
||||
add
|
||||
{
|
||||
AddHandler( ItemAddingEvent, value );
|
||||
}
|
||||
remove
|
||||
{
|
||||
RemoveHandler( ItemAddingEvent, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemAdding Event
|
||||
|
||||
#region ItemAdded Event
|
||||
|
||||
public delegate void ItemAddedRoutedEventHandler( object sender, ItemEventArgs e );
|
||||
|
||||
public static readonly RoutedEvent ItemAddedEvent = EventManager.RegisterRoutedEvent( "ItemAdded", RoutingStrategy.Bubble, typeof( ItemAddedRoutedEventHandler ), typeof( CollectionControl ) );
|
||||
public event ItemAddedRoutedEventHandler ItemAdded
|
||||
{
|
||||
add
|
||||
{
|
||||
AddHandler( ItemAddedEvent, value );
|
||||
}
|
||||
remove
|
||||
{
|
||||
RemoveHandler( ItemAddedEvent, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemAdded Event
|
||||
|
||||
#region ItemMovedDown Event
|
||||
|
||||
public delegate void ItemMovedDownRoutedEventHandler( object sender, ItemEventArgs e );
|
||||
|
||||
public static readonly RoutedEvent ItemMovedDownEvent = EventManager.RegisterRoutedEvent( "ItemMovedDown", RoutingStrategy.Bubble, typeof( ItemMovedDownRoutedEventHandler ), typeof( CollectionControl ) );
|
||||
public event ItemMovedDownRoutedEventHandler ItemMovedDown
|
||||
{
|
||||
add
|
||||
{
|
||||
AddHandler( ItemMovedDownEvent, value );
|
||||
}
|
||||
remove
|
||||
{
|
||||
RemoveHandler( ItemMovedDownEvent, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemMovedDown Event
|
||||
|
||||
#region ItemMovedUp Event
|
||||
|
||||
public delegate void ItemMovedUpRoutedEventHandler( object sender, ItemEventArgs e );
|
||||
|
||||
public static readonly RoutedEvent ItemMovedUpEvent = EventManager.RegisterRoutedEvent( "ItemMovedUp", RoutingStrategy.Bubble, typeof( ItemMovedUpRoutedEventHandler ), typeof( CollectionControl ) );
|
||||
public event ItemMovedUpRoutedEventHandler ItemMovedUp
|
||||
{
|
||||
add
|
||||
{
|
||||
AddHandler( ItemMovedUpEvent, value );
|
||||
}
|
||||
remove
|
||||
{
|
||||
RemoveHandler( ItemMovedUpEvent, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemMovedUp Event
|
||||
|
||||
#endregion
|
||||
|
||||
#region EventHandlers
|
||||
|
||||
void NewItemTypesComboBox_Loaded( object sender, RoutedEventArgs e )
|
||||
{
|
||||
if( _newItemTypesComboBox != null )
|
||||
_newItemTypesComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void PropertyGrid_PropertyValueChanged( object sender, PropertyGrid.PropertyValueChangedEventArgs e )
|
||||
{
|
||||
if( _listBox != null )
|
||||
{
|
||||
_listBox.Items.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
private void AddNew( object sender, ExecutedRoutedEventArgs e )
|
||||
{
|
||||
var newItem = CreateNewItem( ( Type )e.Parameter );
|
||||
var properties = newItem.GetType().GetProperties();
|
||||
foreach( var property in properties )
|
||||
{
|
||||
// For Generic Types, add an empty collection/list of T.
|
||||
if( property.CanWrite && property.PropertyType.IsGenericType )
|
||||
{
|
||||
var genericCollection = Activator.CreateInstance( property.PropertyType );
|
||||
property.SetValue( newItem, genericCollection, null );
|
||||
}
|
||||
}
|
||||
|
||||
var eventArgs = new ItemAddingEventArgs( ItemAddingEvent, newItem );
|
||||
this.RaiseEvent( eventArgs );
|
||||
if( eventArgs.Cancel )
|
||||
return;
|
||||
newItem = eventArgs.Item;
|
||||
|
||||
Items.Add( newItem );
|
||||
|
||||
this.RaiseEvent( new ItemEventArgs( ItemAddedEvent, newItem ) );
|
||||
|
||||
SelectedItem = newItem;
|
||||
}
|
||||
|
||||
private void CanAddNew( object sender, CanExecuteRoutedEventArgs e )
|
||||
{
|
||||
Type t = e.Parameter as Type;
|
||||
if( (t != null) && !this.IsReadOnly )
|
||||
{
|
||||
bool isComplexStruct = t.IsValueType && !t.IsEnum && !t.IsPrimitive;
|
||||
|
||||
if( isComplexStruct || (t.GetConstructor( Type.EmptyTypes ) != null) )
|
||||
{
|
||||
e.CanExecute = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Delete( object sender, ExecutedRoutedEventArgs e )
|
||||
{
|
||||
var eventArgs = new ItemDeletingEventArgs( ItemDeletingEvent, e.Parameter );
|
||||
this.RaiseEvent( eventArgs );
|
||||
if( eventArgs.Cancel )
|
||||
return;
|
||||
|
||||
Items.Remove( e.Parameter );
|
||||
|
||||
this.RaiseEvent( new ItemEventArgs( ItemDeletedEvent, e.Parameter ) );
|
||||
}
|
||||
|
||||
private void CanDelete( object sender, CanExecuteRoutedEventArgs e )
|
||||
{
|
||||
e.CanExecute = e.Parameter != null && !IsReadOnly;
|
||||
}
|
||||
|
||||
private void MoveDown( object sender, ExecutedRoutedEventArgs e )
|
||||
{
|
||||
var selectedItem = e.Parameter;
|
||||
var index = Items.IndexOf( selectedItem );
|
||||
Items.RemoveAt( index );
|
||||
Items.Insert( ++index, selectedItem );
|
||||
|
||||
this.RaiseEvent( new ItemEventArgs( ItemMovedDownEvent, selectedItem ) );
|
||||
|
||||
SelectedItem = selectedItem;
|
||||
}
|
||||
|
||||
private void CanMoveDown( object sender, CanExecuteRoutedEventArgs e )
|
||||
{
|
||||
if( e.Parameter != null && Items.IndexOf( e.Parameter ) < ( Items.Count - 1 ) && !IsReadOnly )
|
||||
e.CanExecute = true;
|
||||
}
|
||||
|
||||
private void MoveUp( object sender, ExecutedRoutedEventArgs e )
|
||||
{
|
||||
var selectedItem = e.Parameter;
|
||||
var index = Items.IndexOf( selectedItem );
|
||||
Items.RemoveAt( index );
|
||||
Items.Insert( --index, selectedItem );
|
||||
|
||||
this.RaiseEvent( new ItemEventArgs( ItemMovedUpEvent, selectedItem ) );
|
||||
|
||||
SelectedItem = selectedItem;
|
||||
}
|
||||
|
||||
private void CanMoveUp( object sender, CanExecuteRoutedEventArgs e )
|
||||
{
|
||||
if( e.Parameter != null && Items.IndexOf( e.Parameter ) > 0 && !IsReadOnly )
|
||||
e.CanExecute = true;
|
||||
}
|
||||
|
||||
#endregion //Commands
|
||||
|
||||
#region Methods
|
||||
|
||||
public void PersistChanges()
|
||||
{
|
||||
this.PersistChanges( this.Items );
|
||||
}
|
||||
|
||||
internal void PersistChanges( IList sourceList )
|
||||
{
|
||||
var collection = ComputeItemsSource();
|
||||
if( collection == null )
|
||||
return;
|
||||
|
||||
//IDictionary<T> and IDictionary
|
||||
if( collection is IDictionary )
|
||||
{
|
||||
//For a Dictionary, we need to parse the list of EditableKeyValuePair and add KeyValuePair to the Dictionary.
|
||||
var dict = (IDictionary)collection;
|
||||
//the easiest way to persist changes to the source is to just clear the source list and then add all items to it.
|
||||
dict.Clear();
|
||||
|
||||
foreach( var item in sourceList )
|
||||
{
|
||||
var propInfoKey = item.GetType().GetProperty( "Key" );
|
||||
var propInfoValue = item.GetType().GetProperty( "Value" );
|
||||
if( (propInfoKey != null) && (propInfoValue != null) )
|
||||
{
|
||||
dict.Add( propInfoKey.GetValue( item, null ), propInfoValue.GetValue( item, null ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
//IList
|
||||
else if( collection is IList )
|
||||
{
|
||||
var list = (IList)collection;
|
||||
|
||||
//the easiest way to persist changes to the source is to just clear the source list and then add all items to it.
|
||||
list.Clear();
|
||||
|
||||
if( list.IsFixedSize )
|
||||
{
|
||||
for( int i = 0; i < sourceList.Count; ++i )
|
||||
list[ i ] = sourceList[ i ];
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( var item in sourceList )
|
||||
{
|
||||
list.Add( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//ICollection<T> (or IList<T>)
|
||||
var collectionType = collection.GetType();
|
||||
var iCollectionOfTInterface = collectionType.GetInterfaces().FirstOrDefault( x => x.IsGenericType && (x.GetGenericTypeDefinition() == typeof( ICollection<> )) );
|
||||
if( iCollectionOfTInterface != null )
|
||||
{
|
||||
var argumentType = iCollectionOfTInterface.GetGenericArguments().FirstOrDefault();
|
||||
if( argumentType != null )
|
||||
{
|
||||
var iCollectionOfTType = typeof( ICollection<> ).MakeGenericType( argumentType );
|
||||
|
||||
//the easiest way to persist changes to the source is to just clear the source list and then add all items to it.
|
||||
iCollectionOfTType.GetMethod( "Clear" ).Invoke( collection, null );
|
||||
|
||||
foreach( var item in sourceList )
|
||||
{
|
||||
iCollectionOfTType.GetMethod( "Add" ).Invoke( collection, new object[] { item } );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable CreateItemsSource()
|
||||
{
|
||||
IEnumerable collection = null;
|
||||
|
||||
if( ItemsSourceType != null )
|
||||
{
|
||||
var constructor = ItemsSourceType.GetConstructor( Type.EmptyTypes );
|
||||
if( constructor != null )
|
||||
{
|
||||
collection = (IEnumerable)constructor.Invoke( null );
|
||||
}
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
private object CreateNewItem( Type type )
|
||||
{
|
||||
return Activator.CreateInstance( type );
|
||||
}
|
||||
|
||||
private IEnumerable ComputeItemsSource()
|
||||
{
|
||||
if( ItemsSource == null )
|
||||
ItemsSource = CreateItemsSource();
|
||||
|
||||
return ItemsSource;
|
||||
}
|
||||
|
||||
#endregion //Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit
|
||||
{
|
||||
public class CollectionControlButton : Button
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
static CollectionControlButton()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata( typeof( CollectionControlButton ), new FrameworkPropertyMetadata( typeof( CollectionControlButton ) ) );
|
||||
}
|
||||
|
||||
public CollectionControlButton()
|
||||
{
|
||||
this.Click += this.CollectionControlButton_Click;
|
||||
}
|
||||
|
||||
#endregion //Constructors
|
||||
|
||||
#region Properties
|
||||
|
||||
#region IsReadOnly Property
|
||||
|
||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register( "IsReadOnly", typeof( bool ), typeof( CollectionControlButton ), new UIPropertyMetadata( false ) );
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( bool )GetValue( IsReadOnlyProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( IsReadOnlyProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //IsReadOnly
|
||||
|
||||
#region ItemsSource Property
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( "ItemsSource", typeof( IEnumerable ), typeof( CollectionControlButton ), new UIPropertyMetadata( null ) );
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return (IEnumerable)GetValue( ItemsSourceProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemsSource
|
||||
|
||||
#region ItemsSourceType Property
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceTypeProperty = DependencyProperty.Register( "ItemsSourceType", typeof( Type ), typeof( CollectionControlButton ), new UIPropertyMetadata( null ) );
|
||||
public Type ItemsSourceType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( Type )GetValue( ItemsSourceTypeProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceTypeProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //ItemsSourceType
|
||||
|
||||
#region NewItemTypes Property
|
||||
|
||||
public static readonly DependencyProperty NewItemTypesProperty = DependencyProperty.Register( "NewItemTypes", typeof( IList ), typeof( CollectionControlButton ), new UIPropertyMetadata( null ) );
|
||||
public IList<Type> NewItemTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( IList<Type> )GetValue( NewItemTypesProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( NewItemTypesProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //NewItemTypes
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private void CollectionControlButton_Click( object sender, RoutedEventArgs e )
|
||||
{
|
||||
var collectionControlDialog = new CollectionControlDialog();
|
||||
collectionControlDialog.ItemsSource = this.ItemsSource;
|
||||
collectionControlDialog.NewItemTypes = this.NewItemTypes;
|
||||
collectionControlDialog.ItemsSourceType = this.ItemsSourceType;
|
||||
collectionControlDialog.IsReadOnly = this.IsReadOnly;
|
||||
collectionControlDialog.ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<!--***********************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
**********************************************************************************-->
|
||||
|
||||
<local:CollectionControlDialogBase x:Class="Xceed.Wpf.Toolkit.CollectionControlDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Xceed.Wpf.Toolkit"
|
||||
Title="Collection Control"
|
||||
Height="400"
|
||||
Width="600"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<local:CollectionControl x:Name="_collectionControl"
|
||||
ItemsSourceType="{Binding ItemsSourceType, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
|
||||
ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Mode=TwoWay}"
|
||||
NewItemTypes="{Binding NewItemTypes, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
|
||||
IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="5">
|
||||
<Button Width="75"
|
||||
Margin="2"
|
||||
Click="OkButton_Click"
|
||||
IsDefault="True">OK</Button>
|
||||
<Button Width="75"
|
||||
Margin="2"
|
||||
Click="CancelButton_Click"
|
||||
IsCancel="True">Cancel</Button>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</local:CollectionControlDialogBase>
|
||||
@@ -0,0 +1,302 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Xceed.Wpf.Toolkit.Core.Utilities;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit
|
||||
{
|
||||
public partial class CollectionControlDialogBase :
|
||||
Window
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for CollectionControlDialog.xaml
|
||||
/// </summary>
|
||||
public partial class CollectionControlDialog : CollectionControlDialogBase
|
||||
{
|
||||
#region Private Members
|
||||
|
||||
private IList originalData = new List<object>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( "ItemsSource", typeof( IEnumerable ), typeof( CollectionControlDialog ), new UIPropertyMetadata( null ) );
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return (IEnumerable)GetValue( ItemsSourceProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceTypeProperty = DependencyProperty.Register( "ItemsSourceType", typeof( Type ), typeof( CollectionControlDialog ), new UIPropertyMetadata( null ) );
|
||||
public Type ItemsSourceType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( Type )GetValue( ItemsSourceTypeProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceTypeProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty NewItemTypesProperty = DependencyProperty.Register( "NewItemTypes", typeof( IList ), typeof( CollectionControlDialog ), new UIPropertyMetadata( null ) );
|
||||
public IList<Type> NewItemTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( IList<Type> )GetValue( NewItemTypesProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( NewItemTypesProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register( "IsReadOnly", typeof( bool ), typeof( CollectionControlDialog ), new UIPropertyMetadata( false ) );
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( bool )GetValue( IsReadOnlyProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( IsReadOnlyProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
public CollectionControl CollectionControl
|
||||
{
|
||||
get
|
||||
{
|
||||
return _collectionControl;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion //Properties
|
||||
|
||||
#region Constructors
|
||||
|
||||
public CollectionControlDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public CollectionControlDialog( Type itemsourceType )
|
||||
: this()
|
||||
{
|
||||
ItemsSourceType = itemsourceType;
|
||||
}
|
||||
|
||||
public CollectionControlDialog( Type itemsourceType, IList<Type> newItemTypes )
|
||||
: this( itemsourceType )
|
||||
{
|
||||
NewItemTypes = newItemTypes;
|
||||
}
|
||||
|
||||
#endregion //Constructors
|
||||
|
||||
#region Overrides
|
||||
|
||||
protected override void OnSourceInitialized( EventArgs e )
|
||||
{
|
||||
base.OnSourceInitialized( e );
|
||||
|
||||
//Backup data in case "Cancel" is clicked.
|
||||
if( this.ItemsSource != null )
|
||||
{
|
||||
foreach( var item in this.ItemsSource )
|
||||
{
|
||||
originalData.Add( this.Clone( item ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OkButton_Click( object sender, RoutedEventArgs e )
|
||||
{
|
||||
if( this.ItemsSource is IDictionary )
|
||||
{
|
||||
if( !this.AreDictionaryKeysValid() )
|
||||
{
|
||||
MessageBox.Show( "All dictionary items should have distinct non-null Key values.", "Warning" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_collectionControl.PersistChanges();
|
||||
this.DialogResult = true;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void CancelButton_Click( object sender, RoutedEventArgs e )
|
||||
{
|
||||
_collectionControl.PersistChanges( originalData );
|
||||
this.DialogResult = false;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
#endregion //Event Hanlders
|
||||
|
||||
#region Private Methods
|
||||
|
||||
[SecuritySafeCritical]
|
||||
private object Clone( object source )
|
||||
{
|
||||
if( source == null )
|
||||
return null;
|
||||
|
||||
object result = null;
|
||||
var sourceType = source.GetType();
|
||||
|
||||
// For IDictionary, we need to create EditableKeyValuePair to edit the Key-Value.
|
||||
if( (this.ItemsSource is IDictionary)
|
||||
&& sourceType.IsGenericType
|
||||
&& typeof( KeyValuePair<,> ).IsAssignableFrom( sourceType.GetGenericTypeDefinition() ) )
|
||||
{
|
||||
result = this.GenerateEditableKeyValuePair( source );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialized a new object with default values
|
||||
result = FormatterServices.GetUninitializedObject( sourceType );
|
||||
var constructor = sourceType.GetConstructor( Type.EmptyTypes );
|
||||
if( constructor == null )
|
||||
return null;
|
||||
constructor.Invoke( result, null );
|
||||
}
|
||||
Debug.Assert( result != null );
|
||||
if( result != null )
|
||||
{
|
||||
var properties = sourceType.GetProperties();
|
||||
|
||||
foreach( var propertyInfo in properties )
|
||||
{
|
||||
var parameters = propertyInfo.GetIndexParameters();
|
||||
var index = parameters.GetLength( 0 ) == 0 ? null : new object[] { parameters.GetLength( 0 ) - 1 };
|
||||
var propertyInfoValue = propertyInfo.GetValue( source, index );
|
||||
|
||||
if( propertyInfo.CanWrite )
|
||||
{
|
||||
// Look for nested object
|
||||
if( propertyInfo.PropertyType.IsClass
|
||||
&& (propertyInfo.PropertyType != typeof( Transform ))
|
||||
&& !propertyInfo.PropertyType.Equals( typeof( string ) ) )
|
||||
{
|
||||
// We have a Collection/List of T.
|
||||
if( propertyInfo.PropertyType.IsGenericType )
|
||||
{
|
||||
// Clone sub-objects if the T are non-primitive types objects.
|
||||
var arg = propertyInfo.PropertyType.GetGenericArguments().FirstOrDefault();
|
||||
if( (arg != null) && !arg.IsPrimitive && !arg.Equals( typeof( String ) ) && !arg.IsEnum )
|
||||
{
|
||||
var nestedObject = this.Clone( propertyInfoValue );
|
||||
propertyInfo.SetValue( result, nestedObject, null );
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy object if the T are primitive types objects.
|
||||
propertyInfo.SetValue( result, propertyInfoValue, null );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var nestedObject = this.Clone( propertyInfoValue );
|
||||
if( nestedObject != null )
|
||||
{
|
||||
// For T object included in List/Collections, Add it to the List/Collection of T.
|
||||
if( index != null )
|
||||
{
|
||||
result.GetType().GetMethod( "Add" ).Invoke( result, new[] { nestedObject } );
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyInfo.SetValue( result, nestedObject, null );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy regular object
|
||||
propertyInfo.SetValue( result, propertyInfoValue, null );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private object GenerateEditableKeyValuePair( object source )
|
||||
{
|
||||
var sourceType = source.GetType();
|
||||
if( (sourceType.GetGenericArguments() == null) || (sourceType.GetGenericArguments().GetLength( 0 ) != 2) )
|
||||
return null;
|
||||
|
||||
var propInfoKey = sourceType.GetProperty( "Key" );
|
||||
var propInfoValue = sourceType.GetProperty( "Value" );
|
||||
if( (propInfoKey != null) && (propInfoValue != null) )
|
||||
{
|
||||
return ListUtilities.CreateEditableKeyValuePair( propInfoKey.GetValue( source, null )
|
||||
, sourceType.GetGenericArguments()[ 0 ]
|
||||
, propInfoValue.GetValue( source, null )
|
||||
, sourceType.GetGenericArguments()[ 1 ] );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool AreDictionaryKeysValid()
|
||||
{
|
||||
var keys = _collectionControl.Items.Select( x =>
|
||||
{
|
||||
var keyType = x.GetType().GetProperty( "Key" );
|
||||
if( keyType != null )
|
||||
{
|
||||
return keyType.GetValue( x, null );
|
||||
}
|
||||
return null;
|
||||
} );
|
||||
|
||||
return (keys.Distinct().Count() == _collectionControl.Items.Count )
|
||||
&& keys.All( x => x != null );
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Globalization;
|
||||
using Xceed.Wpf.Toolkit.Core.Utilities;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// This multi-value converter is used in the CollectionControl template
|
||||
/// to determine the list of possible new item types that will be shown in the combo box.
|
||||
///
|
||||
/// If the second value (i.e., CollectionControl.NewItemTypes) is not null, this list will be used.
|
||||
/// Otherwise, if the first value (i.e., CollectionControl.ItemsSourceType) is a "IList<T>"
|
||||
/// type, the new item type list will contain "T".
|
||||
///
|
||||
/// </summary>
|
||||
public class NewItemTypesComboBoxConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert( object[] values, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
|
||||
if( values.Length != 2 )
|
||||
throw new ArgumentException("The 'values' argument should contain 2 objects.");
|
||||
|
||||
if( values[ 1 ] != null )
|
||||
{
|
||||
if( !values[ 1 ].GetType().IsGenericType || !(values[ 1 ].GetType().GetGenericArguments().First().GetType() is Type) )
|
||||
throw new ArgumentException( "The 'value' argument is not of the correct type." );
|
||||
|
||||
return values[ 1 ];
|
||||
}
|
||||
else if( values[ 0 ] != null )
|
||||
{
|
||||
if( !( values[ 0 ].GetType() is Type ) )
|
||||
throw new ArgumentException( "The 'value' argument is not of the correct type." );
|
||||
|
||||
List<Type> types = new List<Type>();
|
||||
Type listType = ListUtilities.GetListItemType( ( Type )values[ 0 ] );
|
||||
if( listType != null )
|
||||
{
|
||||
types.Add( listType );
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public object[] ConvertBack( object value, Type[] targetTypes, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Xceed.Wpf.Toolkit.Core;
|
||||
using System.Windows;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit
|
||||
{
|
||||
public class ItemAddingEventArgs : CancelRoutedEventArgs
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
public ItemAddingEventArgs( RoutedEvent itemAddingEvent, object itemAdding )
|
||||
: base( itemAddingEvent )
|
||||
{
|
||||
Item = itemAdding;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
#region Item Property
|
||||
|
||||
public object Item
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion //Properties
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Xceed.Wpf.Toolkit.Core;
|
||||
using System.Windows;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit
|
||||
{
|
||||
public class ItemDeletingEventArgs : CancelRoutedEventArgs
|
||||
{
|
||||
#region Private Members
|
||||
|
||||
private object _item;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public ItemDeletingEventArgs( RoutedEvent itemDeletingEvent, object itemDeleting )
|
||||
: base( itemDeletingEvent )
|
||||
{
|
||||
_item = itemDeleting;
|
||||
}
|
||||
|
||||
#region Property Item
|
||||
|
||||
public object Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return _item;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit
|
||||
{
|
||||
public class ItemEventArgs : RoutedEventArgs
|
||||
{
|
||||
#region Protected Members
|
||||
|
||||
private object _item;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
internal ItemEventArgs( RoutedEvent routedEvent, object newItem )
|
||||
: base( routedEvent )
|
||||
{
|
||||
_item = newItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Property Item
|
||||
|
||||
public object Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return _item;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Extended WPF Toolkit
|
||||
|
||||
Copyright (C) 2007-2013 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Xceed.Wpf.Toolkit
|
||||
{
|
||||
public class PrimitiveTypeCollectionControl : ContentControl
|
||||
{
|
||||
#region Members
|
||||
|
||||
bool _surpressTextChanged;
|
||||
bool _conversionFailed;
|
||||
|
||||
#endregion //Members
|
||||
|
||||
#region Properties
|
||||
|
||||
#region IsOpen
|
||||
|
||||
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register( "IsOpen", typeof( bool ), typeof( PrimitiveTypeCollectionControl ), new UIPropertyMetadata( false, OnIsOpenChanged ) );
|
||||
public bool IsOpen
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( bool )GetValue( IsOpenProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( IsOpenProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnIsOpenChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
PrimitiveTypeCollectionControl primitiveTypeCollectionControl = o as PrimitiveTypeCollectionControl;
|
||||
if( primitiveTypeCollectionControl != null )
|
||||
primitiveTypeCollectionControl.OnIsOpenChanged( ( bool )e.OldValue, ( bool )e.NewValue );
|
||||
}
|
||||
|
||||
protected virtual void OnIsOpenChanged( bool oldValue, bool newValue )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion //IsOpen
|
||||
|
||||
#region ItemsSource
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( "ItemsSource", typeof( IList ), typeof( PrimitiveTypeCollectionControl ), new UIPropertyMetadata( null, OnItemsSourceChanged ) );
|
||||
public IList ItemsSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( IList )GetValue( ItemsSourceProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnItemsSourceChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
PrimitiveTypeCollectionControl primitiveTypeCollectionControl = o as PrimitiveTypeCollectionControl;
|
||||
if( primitiveTypeCollectionControl != null )
|
||||
primitiveTypeCollectionControl.OnItemsSourceChanged( ( IList )e.OldValue, ( IList )e.NewValue );
|
||||
}
|
||||
|
||||
protected virtual void OnItemsSourceChanged( IList oldValue, IList newValue )
|
||||
{
|
||||
if( newValue == null )
|
||||
return;
|
||||
|
||||
if( ItemsSourceType == null )
|
||||
ItemsSourceType = newValue.GetType();
|
||||
|
||||
if( ItemType == null && newValue.GetType().ContainsGenericParameters )
|
||||
ItemType = newValue.GetType().GetGenericArguments()[ 0 ];
|
||||
|
||||
SetText( newValue );
|
||||
}
|
||||
|
||||
#endregion //ItemsSource
|
||||
|
||||
#region IsReadOnly
|
||||
|
||||
public static readonly DependencyProperty IsReadOnlyProperty =
|
||||
DependencyProperty.Register( "IsReadOnly", typeof( bool ), typeof( PrimitiveTypeCollectionControl ), new UIPropertyMetadata( false ) );
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return ( bool )GetValue( IsReadOnlyProperty ); }
|
||||
set { SetValue( IsReadOnlyProperty, value ); }
|
||||
}
|
||||
|
||||
#endregion //IsReadOnly
|
||||
|
||||
#region ItemsSourceType
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceTypeProperty = DependencyProperty.Register( "ItemsSourceType", typeof( Type ), typeof( PrimitiveTypeCollectionControl ), new UIPropertyMetadata( null ) );
|
||||
public Type ItemsSourceType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( Type )GetValue( ItemsSourceTypeProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemsSourceTypeProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion ItemsSourceType
|
||||
|
||||
#region ItemType
|
||||
|
||||
public static readonly DependencyProperty ItemTypeProperty = DependencyProperty.Register( "ItemType", typeof( Type ), typeof( PrimitiveTypeCollectionControl ), new UIPropertyMetadata( null ) );
|
||||
public Type ItemType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( Type )GetValue( ItemTypeProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( ItemTypeProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion ItemType
|
||||
|
||||
#region Text
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof( string ), typeof( PrimitiveTypeCollectionControl ), new UIPropertyMetadata( null, OnTextChanged ) );
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return ( string )GetValue( TextProperty );
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue( TextProperty, value );
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnTextChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
PrimitiveTypeCollectionControl primitiveTypeCollectionControl = o as PrimitiveTypeCollectionControl;
|
||||
if( primitiveTypeCollectionControl != null )
|
||||
primitiveTypeCollectionControl.OnTextChanged( ( string )e.OldValue, ( string )e.NewValue );
|
||||
}
|
||||
|
||||
protected virtual void OnTextChanged( string oldValue, string newValue )
|
||||
{
|
||||
if( !_surpressTextChanged )
|
||||
PersistChanges();
|
||||
}
|
||||
|
||||
#endregion //Text
|
||||
|
||||
#endregion //Properties
|
||||
|
||||
#region Constructors
|
||||
|
||||
static PrimitiveTypeCollectionControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata( typeof( PrimitiveTypeCollectionControl ), new FrameworkPropertyMetadata( typeof( PrimitiveTypeCollectionControl ) ) );
|
||||
}
|
||||
|
||||
public PrimitiveTypeCollectionControl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion //Constructors
|
||||
|
||||
#region Methods
|
||||
|
||||
private void PersistChanges()
|
||||
{
|
||||
IList list = ComputeItemsSource();
|
||||
if( list == null )
|
||||
return;
|
||||
|
||||
IList items = ComputeItems();
|
||||
|
||||
//the easiest way to persist changes to the source is to just clear the source list and then add all items to it.
|
||||
list.Clear();
|
||||
|
||||
foreach( var item in items )
|
||||
{
|
||||
list.Add( item );
|
||||
};
|
||||
|
||||
// if something went wrong during conversion we want to reload the text to show only valid entries
|
||||
if( _conversionFailed )
|
||||
SetText( list );
|
||||
}
|
||||
|
||||
private IList ComputeItems()
|
||||
{
|
||||
IList items = new List<object>();
|
||||
|
||||
if( ItemType == null )
|
||||
return items;
|
||||
|
||||
string[] textArray = Text.Split( '\n' );
|
||||
|
||||
foreach( string s in textArray )
|
||||
{
|
||||
string valueString = s.TrimEnd( '\r' );
|
||||
if( !String.IsNullOrEmpty( valueString ) )
|
||||
{
|
||||
object value = null;
|
||||
try
|
||||
{
|
||||
if( ItemType.IsEnum )
|
||||
{
|
||||
value = Enum.Parse( ItemType, valueString );
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Convert.ChangeType( valueString, ItemType );
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//a conversion failed
|
||||
_conversionFailed = true;
|
||||
}
|
||||
|
||||
if( value != null )
|
||||
items.Add( value );
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private IList ComputeItemsSource()
|
||||
{
|
||||
if( ItemsSource == null )
|
||||
{
|
||||
// Save current text since creating the ItemsSource will reset it
|
||||
string currentText = this.Text;
|
||||
ItemsSource = CreateItemsSource();
|
||||
this.Text = currentText;
|
||||
}
|
||||
|
||||
return ItemsSource;
|
||||
}
|
||||
|
||||
private IList CreateItemsSource()
|
||||
{
|
||||
IList list = null;
|
||||
|
||||
if( ItemsSourceType != null )
|
||||
{
|
||||
ConstructorInfo constructor = ItemsSourceType.GetConstructor( Type.EmptyTypes );
|
||||
list = ( IList )constructor.Invoke( null );
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private void SetText( IEnumerable collection )
|
||||
{
|
||||
_surpressTextChanged = true;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach( object obj2 in collection )
|
||||
{
|
||||
builder.Append( obj2.ToString() );
|
||||
builder.AppendLine();
|
||||
}
|
||||
Text = builder.ToString().Trim();
|
||||
_surpressTextChanged = false;
|
||||
}
|
||||
|
||||
#endregion //Methods
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user