简而言之:手动调用dispose并将reference设置为null不会从宿主窗口释放用户控件实例。
我附上了蚂蚁的内存档案截图,显示了它在其中保持生存的层次结构。在我看来,一个互操作调用仍然挂起/引用
HwndKeyboardInputProvider
. 如果假设是正确的,那么我不确定如何在dispose方法中获取此非托管引用的句柄以进行dispose。
有人能帮我实现对我的用户控件实例的清理处理吗?
<UserControl x:Class="CTWPFControls.CTWPFTextbox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Name="ctTextBox"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="root">
<TextBox d:LayoutOverrides="Width" Name="textBox1" VerticalAlignment="Bottom"
Text="{Binding ElementName=ctTextBox, Path=BindText}" LostFocus="TextBox_LostFocus"
TextChanged="textBox1_TextChanged" PreviewTextInput="textBox1_PreviewTextInput"
GotFocus="TextBox_GotFocus" SpellCheck.IsEnabled="{Binding ElementName=ctTextBox, Path=EnableSpellCheck}" />
</Grid>
</UserControl>
代码隐藏
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.ComponentModel;
namespace CTWPFControls
{
/// <summary>
/// Interaction logic for CTWPFTextbox.xaml
/// </summary>
public partial class CTWPFTextbox : UserControl,IDisposable
{
public void Dispose()
{
textBox1.TextChanged -= textBox1_TextChanged;
textBox1.PreviewTextInput -= textBox1_PreviewTextInput;
textBox1.GotFocus -= TextBox_GotFocus;
textBox1.LostFocus -= TextBox_LostFocus;
textBox1.KeyDown -= TextBox_OnKeyDown;
textBox1 = null;
ctTextBox = null;
}
// Need this for binding in the credit search....or anywhere else for that matter
public static DependencyProperty TextProperty = DependencyProperty.Register("BindText", typeof(string), typeof(CTWPFTextbox));
public static DependencyProperty CanEnableSpellCheckProperty = DependencyProperty.Register(
"EnableSpellCheck", typeof(bool), typeof(CTWPFTextbox));
public event TextChangedEventHandler TextChanged;
public bool EnableSpellCheck
{
get { return (bool)GetValue(SpellCheck.IsEnabledProperty); }
set { SetValue(SpellCheck.IsEnabledProperty, value); }
}
public string BindText
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public enum EditType { AlphaNumeric, Numeric, Alphabetic, Telephone, NoSymbols, Decimal, Money, Date, IncomeExpText, LookupSearch }
public string Text
{
get { return this.textBox1.Text; }
set
{
string controlText;
controlText = this.ValidateControlText(value);
if (this.TextBoxType == EditType.AlphaNumeric || this.TextBoxType == EditType.Alphabetic || this.TextBoxType == EditType.NoSymbols)
if (this.AutoFormat)
controlText = ValidateAlphaTextBox(controlText);
if (this.TextBoxType == EditType.Numeric || this.TextBoxType == EditType.IncomeExpText)
if (this.AutoFormat)
controlText = this.FormatNumeric(controlText);
this.textBox1.Text = controlText;
}
}
public int MaxLength
{
get { return this.textBox1.MaxLength; }
set { textBox1.MaxLength = value; }
}
public bool ReadOnly
{
get { return this.textBox1.IsReadOnly; }
set { this.textBox1.IsReadOnly = value; }
}
public TextWrapping TextWrap
{
get { return this.textBox1.TextWrapping; }
set { this.textBox1.TextWrapping = value; }
}
[DefaultValue(EditType.AlphaNumeric)]
public EditType TextBoxType { get; set; }
[DefaultValue(false)]
public bool HasDecimals { get; set; }
[DefaultValue(true)]
public bool AutoFormat { get; set; }
public CTWPFTextbox()
{
InitializeComponent();
}
private string FormatNumeric(string controlText)
{
decimal controlValue;
string returnValue;
if (controlText == string.Empty)
return string.Empty;
if (controlText.IndexOf(".") == 0)
{
if (controlText.Length == 1)
returnValue = "0";
else
returnValue = string.Format("0{0}", controlText);
}
try { controlValue = decimal.Parse(controlText); }
catch { return controlText; }
if (!this.HasDecimals)
{
System.Globalization.NumberFormatInfo format = (new System.Globalization.CultureInfo("en-gb")).NumberFormat;
format.NumberDecimalDigits = 0;
returnValue = controlValue.ToString("n", format);
}
else
returnValue = controlValue.ToString("N");
return returnValue;
}
private static bool IsValidOtherKey(Key key)
{
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0)
return true;
if ((key < Key.D0 && key != Key.Space) || (key > Key.Z && key < Key.NumPad0))
return true;
return false;
}
private static bool IsValidDecimalKey(TextBox textBox, Key key)
{
if (IsValidIntegerKey(textBox, key))
return true;
if (key == Key.Decimal)
return !textBox.Text.Contains(".");
return false;
}
private static bool IsValidIntegerKey(TextBox textBox, Key key)
{
if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0)
return false;
if (Key.D0 <= key && key <= Key.D9)
return true;
if (Key.NumPad0 <= key && key <= Key.NumPad9)
return true;
return false;
}
public static string ValidateAlphaTextBox(string controlText)
{
int currentPosition = 0;
string currentWord = string.Empty;
string returnText = string.Empty;
char currentCharacter;
if (controlText == null || controlText.Length == 0)
return string.Empty;
while (currentPosition < controlText.Length)
{
currentCharacter = controlText[currentPosition];
if (currentCharacter == '\t' || currentCharacter == '\n' || currentCharacter == ' ')
{
if (currentWord.Length != 0)
{
currentWord = string.Format("{0}{1}", currentWord.Substring(0, 1).ToUpper(),
currentWord.Length == 1 ? string.Empty : currentWord.Substring(1, currentWord.Length - 1).ToLower());
}
returnText += currentWord + currentCharacter;
currentWord = string.Empty;
}
else
currentWord += currentCharacter;
currentPosition++;
}
if (currentWord.Length != 0)
{
currentWord = string.Format("{0}{1}", currentWord.Substring(0, 1).ToUpper(),
currentWord.Length == 1 ? string.Empty : currentWord.Substring(1, currentWord.Length - 1).ToLower());
returnText += currentWord;
}
return returnText;
}
private string ValidateControlText(string controlText)
{
char[] characterArray;
string textValue = string.Empty;
if (controlText == null)
return string.Empty;
// Allow any text in the alpha numeric control
if (this.TextBoxType == EditType.AlphaNumeric)
return controlText.Replace("'", "`");
// Remove anything after the decimal point for numberic type if decimals are not allowed
if (this.HasDecimals == false && this.TextBoxType == EditType.Numeric)
{
int decimalIndex;
if ((decimalIndex = controlText.IndexOf(".")) != -1)
controlText = controlText.Substring(0, decimalIndex);
}
// Retrieve the string as a character array
characterArray = controlText.ToCharArray();
// Step through each character validating it
for (int index = 0; index < characterArray.Length; index++)
{
switch (this.TextBoxType)
{
case EditType.Alphabetic:
if (this.ValidateAlphabeticInput(characterArray[index]))
textValue += characterArray[index];
break;
case EditType.Numeric:
if (this.ValidateNumericInput(characterArray[index]))
textValue += characterArray[index];
break;
case EditType.IncomeExpText:
if (this.ValidateNumericInput(characterArray[index]))
textValue += characterArray[index];
break;
case EditType.Telephone:
if (this.ValidateNumericInput(characterArray[index]))
textValue += characterArray[index];
break;
case EditType.NoSymbols:
if (this.ValidateNoSymbolInput(characterArray[index]))
textValue += characterArray[index];
break;
case EditType.Decimal:
if (this.ValidateDecimalInput(characterArray[index]))
textValue += characterArray[index];
break;
}
}
// Set the control's text
return textValue;
}
private bool ValidateAlphabeticInput(char keyChar)
{
char[] validCharacters = new char[] { ' ', '`', ',', '.', '-', '_', '@', '/' };
// Check if the character is part of the lower case alphabet
if (keyChar >= 'a' && keyChar <= 'z')
return true;
// Check if the character is part of the upper case alphabet
if (keyChar >= 'A' && keyChar <= 'Z')
return true;
// Step through our list of valid characters
foreach (char validCharacter in validCharacters)
{
// If the character is in the list of characters, it is valid
if (validCharacter == (char)keyChar)
return true;
}
// The character inputted is not allowed in this mode
return false;
}
private bool ValidateNumericInput(char keyChar)
{
// Check if the character is a numeric character
if (keyChar >= '0' && keyChar <= '9')
return true;
if (this.TextBoxType == EditType.Numeric || this.TextBoxType == EditType.Decimal)
{
// If the character is a decimal place, ensure it is the only one
if (keyChar == '.' && this.Text.IndexOf('.') == -1 && this.HasDecimals)
return true;
}
// Do not allow the character
return false;
}
private bool ValidateDecimalInput(char keyChar)
{
// Check if the character is a numeric character
if (keyChar >= '0' && keyChar <= '9')
return true;
// If the character is a decimal place, ensure it is the only one
if (keyChar == '.')
return true;
// Do not allow the character
return false;
}
private bool ValidateNoSymbolInput(char keyChar)
{
// Check if the character is part of the lower case alphabet
if (keyChar >= 'a' && keyChar <= 'z')
return true;
// Check if the character is part of the upper case alphabet
if (keyChar >= 'A' && keyChar <= 'Z')
return true;
// Allow numerical digits
if (keyChar >= '0' && keyChar <= '9')
return true;
// Allow the space character
if (keyChar == ' ')
return true;
// The character inputted is not allowed in this mode
return false;
}
public static bool IsValidAlphaKey(Key key)
{
if ((Key.A <= key && key <= Key.Z) || key == Key.Space)
{
return true;
}
return false;
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
if (this.textBox1.Text.Length == 0 && (TextBoxType != EditType.Telephone && TextBoxType != EditType.Alphabetic && TextBoxType != EditType.AlphaNumeric && TextBoxType != EditType.IncomeExpText && TextBoxType != EditType.LookupSearch))
{
this.textBox1.Text = "0";
return;
}
else if (TextBoxType == EditType.Money)
{
double temp = double.Parse(this.textBox1.Text);
this.textBox1.Text = Math.Round(temp, 2).ToString();
}
else if (TextBoxType == EditType.Numeric || TextBoxType == EditType.IncomeExpText)
{
this.textBox1.Text = this.FormatNumeric(this.textBox1.Text);
}
else if (TextBoxType == EditType.Alphabetic)
{
this.textBox1.Text = ValidateAlphaTextBox(this.textBox1.Text);
}
}
private void TextBox_OnKeyDown(object sender, KeyEventArgs e)
{
if (IsValidOtherKey(e.Key))
return;
if (TextBoxType == EditType.Numeric || TextBoxType == EditType.Telephone || TextBoxType == EditType.IncomeExpText)
e.Handled = !IsValidIntegerKey(this.textBox1, e.Key);
else if (TextBoxType == EditType.Decimal || TextBoxType == EditType.Money)
e.Handled = !IsValidDecimalKey(this.textBox1, e.Key);
else if (TextBoxType == EditType.Alphabetic)
e.Handled = !IsValidAlphaKey(e.Key);
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
if (this.textBox1.Text.Length == 0)
{
base.OnGotFocus(e);
this.textBox1.Focus();
return;
}
if (this.TextBoxType == EditType.Numeric || this.TextBoxType == EditType.IncomeExpText)
this.textBox1.Text = this.textBox1.Text.Replace(",", string.Empty);
this.textBox1.SelectionStart = 0;
this.textBox1.SelectionLength = this.textBox1.Text.Length;
base.OnGotFocus(e);
this.textBox1.Focus();
}
private void textBox1_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (TextBoxType == EditType.Numeric || TextBoxType == EditType.Telephone || TextBoxType == EditType.IncomeExpText)
e.Handled = IsValidNewIntegerKey(e.Text);
else if (TextBoxType == EditType.Alphabetic)
e.Handled = IsValidNewAlphaKey(e.Text);
else if (TextBoxType == EditType.LookupSearch)
e.Handled = IsValidLookupKey(e.Text);
}
public static bool IsValidNewAlphaKey(string key)
{
if (key == " ")
return false;
string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-'";
if (allowedChars.IndexOf(key) >= 0)
return false;
else
return true;
}
public static bool IsValidLookupKey(string key)
{
string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-'%0123456789";
if (allowedChars.IndexOf(key) >= 0)
return false;
else
return true;
}
private static bool IsValidNewIntegerKey(string key)
{
string allowedChars = "0123456789";
if (allowedChars.IndexOf(key) >= 0)
return false;
else
return true;
}
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
TextChangedEventHandler h = TextChanged;
if (h != null)
h(this, e);
}
}
}
参考文献:
-
如果有帮助的话,MSDN论坛上也报道过类似的问题,但解决方案在这方面还不够明确
. 我正在标记链接
here