Silverlight4 deep copy visual element - silverlight

I have a custom visual element and i want to make a deep copy in my silverlight application.
I've tried many things but i didn't find any solution...
Here the best solution that i found but the original DeviceControl and the copy are linked.
If i change a property of one of them, the second also changes. I want them to be independent!
Have you got an idea?
void CloneDevice()
{
DeviceControl control = this;
DeviceControl copy = CloneObject.DeepClone<DeviceControl>(control);
ExtensionMethods.DeepCopy(control, copy);
}
//[Obfuscation(Exclude = true)]
internal static class CloneObject
{
private static bool _firstTry = false;
private static List<FieldInfo> _attachedProperties = null;
// Extension for any class object
internal static TT DeepClone<TT>(this TT source, bool?cloneAttachedProperties = null)
{ // Jim McCurdy's DeepClone
if (cloneAttachedProperties == null)
cloneAttachedProperties = (source is DependencyObject);
// The first time this method is called, compute a list of all
// attached properties that exist in this XAP's assemblies
if (cloneAttachedProperties == true && _attachedProperties == null)
{
_attachedProperties = new List<FieldInfo>();
List<Assembly> assemblies = GetLoadedAssemblies();
foreach (Assembly assembly in assemblies)
GetAttachedProperties(_attachedProperties, assembly);
}
TT clone = CloneRecursive(source);
if (clone is FrameworkElement)
{
FrameworkElement cloneElement = (clone as FrameworkElement);
cloneElement.Arrange(new Rect(0, 0, cloneElement.ActualWidth, cloneElement.ActualHeight));
}
return clone;
}
private static TT CloneRecursive<TT>(TT source)
{
if (source == null || source.GetType().IsValueType)
return source;
// Common types that do not have parameterless constructors
if (source is string || source is Type || source is Uri || source is DependencyProperty)
return source;
TT clone = CloneCreate(source);
if (clone == null)
return source;
if (source is IList)
CloneList(source as IList, clone as IList);
//CloneProperties(source, clone);//ca plante si on prend les propriétées comme ca
return clone;
}
private static TT CloneCreate<TT>(TT source)
{
try
{
#if DEBUG_TRACE
string.Format("Clone create object Type={0}", SimpleType(source.GetType())).Trace();
#endif
Array sourceArray = (source as Array);
if (sourceArray == null)
return (TT)Activator.CreateInstance(source.GetType());
if (sourceArray.Rank == 1)
return (TT)(object)Array.CreateInstance(source.GetType().GetElementType(),
sourceArray.GetLength(0));
if (sourceArray.Rank == 2)
return (TT)(object)Array.CreateInstance(source.GetType().GetElementType(),
sourceArray.GetLength(0), sourceArray.GetLength(1));
}
catch (Exception ex)
{
if (ex.Message.Contains("No parameterless constructor"))
return default(TT);
//string.Format("Can't create object Type={0}", SimpleType(source.GetType())).Trace();
//ex.DebugOutput();
}
return default(TT);
}
private static void CloneProperties(object source, object clone)
{
// The binding flags indicate what properties we will clone
// Unfortunately, we cannot clone "internal" or "protected" properties
BindingFlags flags =
BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public;
if (source is DependencyObject)
{
DependencyObject sourcedp = source as DependencyObject;
DependencyObject clonedp = clone as DependencyObject;
// Clone attached properties
if (_attachedProperties != null && _attachedProperties.Count > 0)
foreach (FieldInfo field in _attachedProperties)
CloneDependencyProperty(sourcedp, clonedp, field, true);
// Clone dependency properties
FieldInfo[] fields = source.GetType().GetFields(flags | BindingFlags.Static);
foreach (FieldInfo field in fields)
CloneDependencyProperty(sourcedp, clonedp, field, false);
}
// Clone CLR properties
if (source is DeviceControl && _firstTry == false)
{
_firstTry = true;
PropertyInfo[] properties = source.GetType().GetProperties(flags);
foreach (PropertyInfo property in properties)
CloneProperty(source, clone, property);
}
}
private static void CloneDependencyProperty(DependencyObject sourceObject,
DependencyObject cloneObject, FieldInfo field, bool isAttached)
{
try
{
// Blacklisted properties that can't (or shouldn't) be set
if (field.Name == "NameProperty" && sourceObject is FrameworkElement) return;
DependencyProperty dp = field.GetValue(sourceObject) as DependencyProperty;
if (dp == null) // Event DependencyProperties will be null
return;
object sourceValue = null;
try
{
sourceValue = sourceObject.GetValue(dp);
}
catch (Exception)
{
}
if (sourceValue == null)
return;
// Don't set attached properties if we don't have to
if (isAttached)
{
Type sourceType = sourceValue.GetType();
if (sourceType.IsValueType && sourceValue.Equals(Activator.CreateInstance(sourceType)))
return;
}
#if DEBUG_TRACE
string.Format("Clone dependency property Name={0}, Value={2} for source Type={1}",
field.Name, SimpleType(sourceObject.GetType()), sourceValue).Trace();
#endif
// Blacklisted properties that can't (or don't need to be) cloned
bool doClone = true;
if (field.Name == "DataContextProperty") doClone = false;
//if (field.Name == "TargetPropertyProperty") doClone = false;
object cloneValue = (doClone ? CloneRecursive(sourceValue) : sourceValue);
cloneObject.SetValue(dp, cloneValue);
}
catch (Exception ex)
{
if (ex.Message.Contains("read-only"))
return;
if (ex.Message.Contains("read only"))
return;
if (ex.Message.Contains("does not fall within the expected range"))
return;
//string.Format("Can't clone dependency property Name={0}, for source Type={1}",
// field.Name, SimpleType(sourceObject.GetType())).Trace();
//ex.DebugOutput();
}
}
private static void CloneProperty(object source, object clone, PropertyInfo property)
{
try
{
if (!property.CanRead || !property.CanWrite || property.GetIndexParameters().Length != 0)
return;
// Blacklisted properties that can't (or shouldn't) be set
if (property.Name == "Name" && source is FrameworkElement) return;
if (property.Name == "InputScope" && source is TextBox) return; // Can't get
if (property.Name == "Watermark" && source is TextBox) return; // Can't get
if (property.Name == "Source" && source is ResourceDictionary) return; // Can't set
if (property.Name == "TargetType" && source is ControlTemplate) return; // Can't set
bool publicSetter = (source.GetType().GetMethod("set_" + property.Name) != null);
bool isList = (property.PropertyType.GetInterface("IList", true) != null);
if (!publicSetter && !isList)
return;
object sourceValue = property.GetValue(source, null);
if (sourceValue == null)
return;
if (!publicSetter && isList)
{
IList cloneList = property.GetValue(clone, null) as IList;
if (cloneList != null)
CloneList(sourceValue as IList, cloneList);
return;
}
#if DEBUG_TRACE
string.Format("Clone property Type={0}, Name={1}, Value={3} for source Type={2}",
SimpleType(property.PropertyType), property.Name, SimpleType(source.GetType()),
sourceValue).Trace();
#endif
// Blacklisted properties that can't (or don't need to be) cloned
bool doClone = true;
if (source is FrameworkElement && property.Name == "DataContext") doClone = false;
//if (property.Name == "TargetProperty") doClone = false;
object cloneValue = (doClone ? CloneRecursive(sourceValue) : sourceValue);
property.SetValue(clone, cloneValue, null); // possible MethodAccessException
}
catch (Exception ex)
{
//string.Format("Can't clone property Type={0}, Name={1}, for source Type={2}",
// SimpleType(property.PropertyType), property.Name, SimpleType(source.GetType())).Trace();
//ex.DebugOutput();
}
}
private static void CloneList(IList sourceList, IList cloneList)
{
try
{
IEnumerator sourceEnumerator = sourceList.GetEnumerator();
Array sourceArray = sourceList as Array;
Array cloneArray = cloneList as Array;
int dim0 = (sourceArray != null && sourceArray.Rank > 0 ? sourceArray.GetLowerBound(0) : 0);
int dim1 = (sourceArray != null && sourceArray.Rank > 1 ? sourceArray.GetLowerBound(1) : 0);
while (sourceEnumerator.MoveNext())
{
object sourceValue = sourceEnumerator.Current;
#if DEBUG_TRACE
string.Format("Clone IList item {0}", sourceValue).Trace();
#endif
object cloneValue = CloneRecursive(sourceValue);
if (sourceArray == null)
cloneList.Add(cloneValue);
else
if (sourceArray.Rank == 1)
cloneArray.SetValue(cloneValue, dim0++);
else
if (sourceArray.Rank == 2)
{
cloneArray.SetValue(cloneValue, dim0, dim1);
if (++dim1 > sourceArray.GetUpperBound(1))
{
dim1 = sourceArray.GetLowerBound(1);
if (++dim0 > sourceArray.GetUpperBound(0))
dim0 = sourceArray.GetLowerBound(0);
}
}
}
}
catch (Exception ex)
{
//string.Format("Can't clone IList item Type={0}", SimpleType(sourceList.GetType())).Trace();
//ex.DebugOutput();
}
}
private static string SimpleType(Type type)
{
string typeName = type.ToString();
int index = typeName.LastIndexOf('[');
if (index < 0)
return typeName.Substring(typeName.LastIndexOf('.') + 1);
string collectionName = typeName.Substring(index);
collectionName = collectionName.Substring(collectionName.LastIndexOf('.') + 1);
typeName = typeName.Substring(0, index);
typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
return typeName + '[' + collectionName;
}
private static List<Assembly> GetLoadedAssemblies()
{
List<Assembly> assemblies = new List<Assembly>();
foreach (AssemblyPart part in Deployment.Current.Parts)
{
StreamResourceInfo sri =
Application.GetResourceStream(new Uri(part.Source, UriKind.Relative));
if (sri == null)
continue;
Assembly assembly = new AssemblyPart().Load(sri.Stream);
if (assembly != null && !assemblies.Contains(assembly))
assemblies.Add(assembly);
}
// Additional assemblies that are not found when examining of Deployment.Current.Parts above
Type[] types =
{
typeof(System.Windows.Application), // System.Windows.dll,
#if INCLUDE_ASSEMBLIES_WITHOUT_ATTACHED_PROPERTIES
typeof(System.Action), // mscorlib.dll,
typeof(System.Uri), // System.dll,
typeof(System.Lazy<int>), // System.Core.dll,
typeof(System.Net.Cookie), // System.Net.dll,
typeof(System.Runtime.Serialization.StreamingContext), // System.Runtime.Serialization.dll,
typeof(System.ServiceModel.XmlSerializerFormatAttribute), // System.ServiceModel.dll,
typeof(System.Windows.Browser.BrowserInformation), // System.Windows.Browser.dll,
typeof(System.Xml.ConformanceLevel), // System.Xml.dll,
#endif
};
foreach (Type type in types)
{
Assembly assembly = type.Assembly;
if (assembly != null && !assemblies.Contains(assembly))
assemblies.Add(assembly);
}
return assemblies;
}
private static bool GetAttachedProperties(List<FieldInfo> attachedProperties, Assembly assembly)
{
BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static;
foreach (Type type in assembly.GetTypes())
{
FieldInfo[] fields = type.GetFields(flags);
MethodInfo[] methods = null;
foreach (FieldInfo field in fields)
{
if (field.FieldType==(typeof(DependencyProperty)))
continue;
if (!field.Name.EndsWith("Property"))
continue;
string fieldName = field.Name.Replace("Property", "");
string getName = "Get" + fieldName;
string setName = "Set" + fieldName;
bool foundGet = false;
bool foundSet = false;
if (methods == null)
methods = type.GetMethods(flags);
foreach (MethodInfo method in methods)
{
if (method.Name == getName && method.GetParameters().Length == 1 &&
method.GetParameters()[0].ParameterType== (typeof(DependencyObject)))
foundGet = true;
else
if (method.Name == setName && method.GetParameters().Length == 2 &&
method.GetParameters()[0].ParameterType==(typeof(DependencyObject)))
foundSet = true;
if (foundGet && foundSet)
break;
}
if (!(foundGet && foundSet))
continue;
try
{
DependencyProperty dp = field.GetValue(null) as DependencyProperty;
}
catch (Exception)
{
continue;
}
// Found an attached Dependency Property
attachedProperties.Add(field);
}
}
return true;
}
}
public static void DeepCopy(object source, object destination)
{
// Get properties
var propertyInfos = source.GetType().GetProperties();
// Evaluate
if (propertyInfos.Length > 0)
{
foreach (var propInfo in propertyInfos)
{
// Process only public properties
if (propInfo.CanWrite)
{
if (propInfo.Name == "IsSelected")
{
break;
}
else
{
object value = propInfo.GetValue(source, null);
propInfo.SetValue(destination, value, null);
// Evaluate
if (value != null)
{
var newPropInfo = value.GetType().GetProperties();
if (newPropInfo.Length > 0)
{
// Copy properties for each child where necessary
DeepCopy(
source.GetType().GetProperty(propInfo.Name),
destination.GetType().GetProperty(propInfo.Name));
}
}
}
}
}
}
}

I solved my issue. I finally used JSon.net library
void CloneDevice()
{
DeviceControl control = this;
string json = JsonConvert.SerializeObject(control, Formatting.Indented);
DeviceControl copy = (DeviceControl)JsonConvert.DeserializeObject(json, this.GetType());
}
Thanks to Olivier Dahan!

Related

InvalidCastException when remove item in ObservableCollection

I am doing a project using WPF and Prims.
When remove category in Categories, an error has occurred.
public ObservableCollection<CategoryModel> _categories;
public ObservableCollection<CategoryModel> Categories
{
get { return _categories; }
set
{
SetProperty(ref _categories, value);
}
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
_journal = navigationContext.NavigationService.Journal;
var category = navigationContext.Parameters["categoryAdd"] as CategoryModel;
if (category != null)
Categories.Add(category);
category = navigationContext.Parameters["categoryDelete"] as CategoryModel;
if (category != null)
{
foreach(var elm in Categories)
if (elm.Id == category.Id)
Categories.Remove(elm); //⇒Error here
}
}
Error:
System.InvalidCastException: 'Cannot cast an object of type' System.Windows.Controls.SelectionChangedEventArgs' to type 'SaleManager.Wpf.Admin.Models.CategoryModel'. '
Why does this error occur? How to fix it?
You can't change a collection in a foreach while reading this collection.
you can do this:
var item = Categories.FirstOrDefault(elm=> elm.Id == category.Id);
Categories.Remove(item);
Use a for loop and iterate backwards. elm is supposed to be a CategoryModel:
if (category != null)
{
for (int i = Categories.Count - 1; i >= 0; --i)
{
CategoryModel elm = Categories[i];
if (elm.Id == category.Id)
{
Categories.Remove(elm);
}
}
}

DataGridComboboxColumn - Get cell value

The task is the following: there is a DataGrid with ComboboxColumns. If user changes cell[2,3] and selected value!=0 then disable cell[3,2]. I wrote the following Handler:
private void grAssessment_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
int x = e.Column.DisplayIndex;
int y = e.Row.GetIndex();
grAssessment.GetCell(x, y).IsEnabled = false;
grAssessment.GetCell(x, y).Background = Brushes.LightGray;
}
But it disables appropriate cell in anyway. How to add selected value!=0 condition to this code?
Thanks in advance.
Try to check this out:
1. DataGridComboBoxColumn ItemsSource (for current version only, use your own):
private ObservableCollection<ScoreData> _scores = new ObservableCollection<ScoreData>(
new List<ScoreData>
{
new ScoreData{Score = 1, ScoreVerbal = "the same"},
new ScoreData{Score = 3, ScoreVerbal = "moderate superiority"},
new ScoreData{Score = 5, ScoreVerbal = "strong superiority"},
new ScoreData{Score = 7, ScoreVerbal = "the samvery strong superioritye"},
new ScoreData{Score = 9, ScoreVerbal = "extremely superiority"},
} );
2. Handler code (the handler defined on the data grid):
private void SelectDataGrid_OnCellEditEnding(object sender,
DataGridCellEditEndingEventArgs e)
{
var editingElement = e.EditingElement as Selector;
if(editingElement == null) return;
var selectedData = editingElement.SelectedItem as ScoreData;
if(selectedData == null || selectedData.Score > 1) return;
var dataGridCell = editingElement.GetVisualParentOfType<DataGridCell>();
if(dataGridCell == null) return;
dataGridCell.IsEnabled = false;
}
3. GetVisualParentOfType code (as part of extension class):
public static class VisualTreeExtensions
{
public static T GetVisualParentOfType<T>(this DependencyObject child)
where T : DependencyObject
{
if (child is T)
return child as T;
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null) return null;
var parent = parentObject as T;
return parent ?? GetVisualParentOfType<T>(parentObject);
}
public static T GetChildOfType<T>(this DependencyObject depObj)
where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
}
regards,
I found the following solution
private void grAssessment_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
int x = e.Column.DisplayIndex;
int y = e.Row.GetIndex();
DataGridCell cell = grAssessment.GetCell(y, x);
if (((System.Windows.Controls.ComboBox)(cell.Content)).Text != "")
{
grAssessment.GetCell(x, y).IsEnabled = false;
grAssessment.GetCell(x, y).Background = Brushes.LightGray;
}
else
{
grAssessment.GetCell(x, y).IsEnabled = true;
grAssessment.GetCell(x, y).Background = Brushes.White;
}
}

WPF ICollectionView Filtering

I've written a code for filtering items in ComboBox:
My question is, how would you do that?
I think that this solution with reflection could be very slow..
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
view.Filter += this.FilterPredicate;
private bool FilterPredicate(object value)
{
if (value == null)
return false;
if (String.IsNullOrEmpty(SearchedText))
return true;
int index = value.ToString().IndexOf(
SearchedText,
0,
StringComparison.InvariantCultureIgnoreCase);
if ( index > -1) return true;
return FindInProperties(new string[] { "Property1", "Property2" }, value, SearchedText);
}
private bool FindInProperties(string[] properties, object value, string txtToFind)
{
PropertyInfo info = null;
for (int i = 0; i < properties.Length; i++)
{
info = value.GetType().GetProperty(properties[i]);
if (info == null) continue;
object s = info.GetValue(value, null);
if (s == null) continue;
int index = s.ToString().IndexOf(
txtToFind,
0,
StringComparison.InvariantCultureIgnoreCase);
if (index > -1) return true;
}
return false;
}
Why not just this:
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
IEqualityComparer<String> comparer = StringComparer.InvariantCultureIgnoreCase;
view.Filter = o => {
Person p = o as Person;
return p.FirstName.Contains(SearchedText, comparer)
|| p.LastName.Contains(SearchedText, comparer);
}
Do you need to search properties dynamically?

Get object by its Uid in WPF

I have an control in WPF which has an unique Uid. How can I retrive the object by its Uid?
You pretty much have to do it by brute-force. Here's a helper extension method you can use:
private static UIElement FindUid(this DependencyObject parent, string uid)
{
var count = VisualTreeHelper.GetChildrenCount(parent);
if (count == 0) return null;
for (int i = 0; i < count; i++)
{
var el = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (el == null) continue;
if (el.Uid == uid) return el;
el = el.FindUid(uid);
if (el != null) return el;
}
return null;
}
Then you can call it like this:
var el = FindUid("someUid");
public static UIElement GetByUid(DependencyObject rootElement, string uid)
{
foreach (UIElement element in LogicalTreeHelper.GetChildren(rootElement).OfType<UIElement>())
{
if (element.Uid == uid)
return element;
UIElement resultChildren = GetByUid(element, uid);
if (resultChildren != null)
return resultChildren;
}
return null;
}
This is better.
public static UIElement FindUid(this DependencyObject parent, string uid) {
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++) {
UIElement el = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (el != null) {
if (el.Uid == uid) { return el; }
el = el.FindUid(uid);
}
}
return null;
}
An issue I had with the top answer is that it won't look inside content controls (such as user controls) for elements within their content. In order to search inside these I extended the function to look at the Content property of compatible controls.
public static UIElement FindUid(this DependencyObject parent, string uid)
{
var count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
var el = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (el == null) continue;
if (el.Uid == uid) return el;
el = el.FindUid(uid);
if (el != null) return el;
}
if (parent is ContentControl)
{
UIElement content = (parent as ContentControl).Content as UIElement;
if (content != null)
{
if (content.Uid == uid) return content;
var el = content.FindUid(uid);
if (el != null) return el;
}
}
return null;
}

Control for tags with auto-completion in Winforms?

I am seeking a WinForm control that would provide an autocomplete behavior for multiple space-separated - exactly ala del.icio.us (or stackoverflow.com for that matter).
Does anyone knows how to do that within a .NET 2.0 WinForm application?
ComboBox can autocomplete, but only one word at a time.
If you want to have each word separately autocompleted, you have to write your own.
I already did, hope it's not too long. It's not 100% exactly what you want, this was used for autocompleting in email client when typing in email adress.
/// <summary>
/// Extended TextBox with smart auto-completion
/// </summary>
public class TextBoxAC: TextBox
{
private List<string> completions = new List<string>();
private List<string> completionsLow = new List<string>();
private bool autocompleting = false;
private bool acDisabled = true;
private List<string> possibleCompletions = new List<string>();
private int currentCompletion = 0;
/// <summary>
/// Default constructor
/// </summary>
public TextBoxAC()
{
this.TextChanged += new EventHandler(TextBoxAC_TextChanged);
this.KeyPress += new KeyPressEventHandler(TextBoxAC_KeyPress);
this.KeyDown += new KeyEventHandler(TextBoxAC_KeyDown);
this.TabStop = true;
}
/// <summary>
/// Sets autocompletion data, list of possible strings
/// </summary>
/// <param name="words">Completion words</param>
/// <param name="wordsLow">Completion words in lowerCase</param>
public void SetAutoCompletion(List<string> words, List<string> wordsLow)
{
if (words == null || words.Count < 1) { return; }
this.completions = words;
this.completionsLow = wordsLow;
this.TabStop = false;
}
private void TextBoxAC_TextChanged(object sender, EventArgs e)
{
if (this.autocompleting || this.acDisabled) { return; }
string text = this.Text;
if (text.Length != this.SelectionStart) { return; }
int pos = this.SelectionStart;
string userPrefix = text.Substring(0, pos);
int commaPos = userPrefix.LastIndexOf(",");
if (commaPos == -1)
{
userPrefix = userPrefix.ToLower();
this.possibleCompletions.Clear();
int n = 0;
foreach (string s in this.completionsLow)
{
if (s.StartsWith(userPrefix))
{
this.possibleCompletions.Add(this.completions[n]);
}
n++;
}
if (this.possibleCompletions.Count < 1) { return; }
this.autocompleting = true;
this.Text = this.possibleCompletions[0];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos;
}
else
{
string curUs = userPrefix.Substring(commaPos + 1);
if (curUs.Trim().Length < 1) { return; }
string trimmed;
curUs = this.trimOut(curUs, out trimmed);
curUs = curUs.ToLower();
string oldUs = userPrefix.Substring(0, commaPos + 1);
this.possibleCompletions.Clear();
int n = 0;
foreach (string s in this.completionsLow)
{
if (s.StartsWith(curUs))
{
this.possibleCompletions.Add(this.completions[n]);
}
n++;
}
if (this.possibleCompletions.Count < 1) { return; }
this.autocompleting = true;
this.Text = oldUs + trimmed + this.possibleCompletions[0];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos + trimmed.Length;
}
this.currentCompletion = 0;
}
private void TextBoxAC_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
{
this.acDisabled = true;
}
if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
{
if ((this.acDisabled) || (this.possibleCompletions.Count < 1))
{
return;
}
e.Handled = true;
if (this.possibleCompletions.Count < 2) { return; }
switch (e.KeyCode)
{
case Keys.Up:
this.currentCompletion--;
if (this.currentCompletion < 0)
{
this.currentCompletion = this.possibleCompletions.Count - 1;
}
break;
case Keys.Down:
this.currentCompletion++;
if (this.currentCompletion >= this.possibleCompletions.Count)
{
this.currentCompletion = 0;
}
break;
}
int pos = this.SelectionStart;
string userPrefix = this.Text.Substring(0, pos);
int commaPos = userPrefix.LastIndexOf(",");
if (commaPos == -1)
{
pos--;
userPrefix = this.Text.Substring(0, pos);
this.autocompleting = true;
this.Text = userPrefix + this.possibleCompletions[this.currentCompletion].Substring(userPrefix.Length);
this.autocompleting = false;
this.SelectionStart = pos + 1;
this.SelectionLength = this.Text.Length - pos;
}
else
{
string curUs = userPrefix.Substring(commaPos + 1);
if (curUs.Trim().Length < 1) { return; }
string trimmed;
curUs = this.trimOut(curUs, out trimmed);
curUs = curUs.ToLower();
string oldUs = userPrefix.Substring(0, commaPos + 1);
this.autocompleting = true;
this.Text = oldUs + trimmed + this.possibleCompletions[this.currentCompletion];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos + trimmed.Length;
}
}
}
private void TextBoxAC_KeyPress(object sender, KeyPressEventArgs e)
{
if (!Char.IsControl(e.KeyChar)) { this.acDisabled = false; }
}
private string trimOut(string toTrim, out string trim)
{
string ret = toTrim.TrimStart();
int pos = toTrim.IndexOf(ret);
trim = toTrim.Substring(0, pos);
return ret;
}
}

Resources