我有以下用户控件:
using CommunityToolkit.Maui.Core.Platform;
using CommunityToolkit.Mvvm.Input;
using System.Diagnostics;
namespace GSL.Presentation.CustomControls;
public partial class GSLEntryControl : ContentView
{
private static Color blue;
private static Color red;
private static Color gray;
public event EventHandler EntryCompleted;
public event EventHandler EntryFocused;
public event EventHandler EntryUnfocused;
private bool isFirstDisplay = true;
public GSLEntryControl()
{
try
{
InitializeComponent();
bool redExists = Application.Current.Resources.TryGetValue("alert_red", out object redValue);
bool blueExists = Application.Current.Resources.TryGetValue("action_color", out object blueValue);
bool grayExists = Application.Current.Resources.TryGetValue("Gray200", out object grayValue);
red = redExists ? (Color)redValue : Colors.Gray;
blue = blueExists ? (Color)blueValue : Colors.Gray;
gray = grayExists ? (Color)grayValue : Colors.Gray;
BorderColor = Color.FromArgb("ffc8c8c8");
}
catch (Exception ex)
{
Debug.WriteLine($"GEORGE: Exception: {ex}");
}
}
[RelayCommand]
private void ClearText()
{
Text = string.Empty;
IsValid = true;
IsClearButtonVisible = false;
}
public static readonly BindableProperty TextProperty = BindableProperty.Create(
nameof(Text),
typeof(string),
typeof(GSLEntryControl),
string.Empty,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
if (bindable is GSLEntryControl editText)
{
editText.Text = newValue?.ToString();
}
});
public static readonly BindableProperty ErrorTextProperty = BindableProperty.Create(
nameof(ErrorText),
typeof(string),
typeof(GSLEntryControl),
string.Empty,
defaultBindingMode: BindingMode.TwoWay);
public static readonly BindableProperty PlaceholderTextProperty = BindableProperty.Create(
nameof(PlaceholderText),
typeof(string),
typeof(GSLEntryControl),
string.Empty,
propertyChanged: (bindable, oldValue, newValue) =>
{
if (bindable is GSLEntryControl editText)
{
editText.PlaceholderText = (string)newValue;
}
});
public static readonly BindableProperty IsPasswordProperty = BindableProperty.Create(
nameof(IsPassword),
typeof(bool),
typeof(GSLEntryControl),
false,
propertyChanged: (bindable, oldValue, newValue) =>
{
if (bindable is GSLEntryControl editText)
{
editText.IsPassword = (bool)newValue;
}
});
public static readonly BindableProperty IsEntryEnabledProperty = BindableProperty.Create(
nameof(IsEntryEnabled),
typeof(bool),
typeof(GSLEntryControl),
true,
propertyChanged: (bindable, oldValue, newValue) =>
{
Debug.WriteLine("George: IsEntryEnabled Start");
if (bindable is GSLEntryControl editText)
{
editText.IsEntryEnabled = (bool)newValue;
}
Debug.WriteLine("George: IsEntryEnabled End");
});
public static readonly BindableProperty IsValidProperty = BindableProperty.Create(
nameof(IsValid),
typeof(bool),
typeof(GSLEntryControl),
true,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
Debug.WriteLine("GEORGE: IsValidProperty Set Start");
if (bindable is GSLEntryControl editText)
{
editText.IsValid = (bool)newValue;
}
Debug.WriteLine("GEORGE: IsValidProperty Set End");
});
// All the updates will be done in the property set.
public static readonly BindableProperty IsInFocusProperty = BindableProperty.Create(
nameof(IsInFocus),
typeof(bool),
typeof(GSLEntryControl),
false,
BindingMode.OneWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
Debug.WriteLine("George: IsInFocusProperty Start");
if (bindable is GSLEntryControl editText)
{
editText.IsInFocus = (bool)newValue;
}
Debug.WriteLine("George: IsInFocusProperty End");
});
public static readonly BindableProperty KeyboardModeProperty = BindableProperty.Create(
nameof(KeyboardMode),
typeof(Keyboard),
typeof(GSLEntryControl),
Keyboard.Default,
BindingMode.OneWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
if (bindable is GSLEntryControl editText)
{
editText.KeyboardMode = (Keyboard)newValue;
}
});
public static readonly BindableProperty KeyboardDisplayModeProperty = BindableProperty.Create(
nameof(KeyboardDisplayMode),
typeof(KeyboardDisplayModeOptions),
typeof(GSLEntryControl),
KeyboardDisplayModeOptions.Always,
BindingMode.OneWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
if (bindable is GSLEntryControl editText)
{
editText.KeyboardDisplayMode = (KeyboardDisplayModeOptions)newValue;
}
});
public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create(
nameof(MaxLength),
typeof(int),
typeof(GSLEntryControl),
100,
BindingMode.OneWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
if (bindable is GSLEntryControl editText)
{
editText.MaxLength = (int)newValue;
}
});
public string _text = string.Empty;
public string Text
{
get
{
return _text;
}
set
{
//Run all this code on the main UI Thread
Application.Current.Dispatcher.Dispatch(() =>
{
Debug.WriteLine("GEORGE: Text Set Start");
_text = value;
IsClearButtonVisible = _text?.Length > 0;
SetBorderColor();
Debug.WriteLine("GEORGE: Text Set End");
});
}
}
public string errorText = string.Empty;
public string ErrorText
{
get
{
return errorText;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
errorText = value;
invalidLabel.Text = errorText;
});
}
}
Color _borderColor = Color.FromArgb("ffc8c8c8");
private Color BorderColor
{
get
{
return _borderColor;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
_borderColor = value;
entryFrame.Stroke = value;
});
}
}
public string _placeholderText = string.Empty;
public string PlaceholderText
{
get
{
return _placeholderText;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
_placeholderText = value;
gslEntry.Placeholder = _placeholderText;
});
}
}
public bool _isPassword = false;
public bool IsPassword
{
get
{
return _isPassword;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
_isPassword = value;
gslEntry.IsPassword = _isPassword;
});
}
}
public bool _isEntryEnabled = true;
public bool IsEntryEnabled
{
get
{
return _isEntryEnabled;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
Debug.WriteLine($"GEORGE: IsEntryEnabled Set Start. Value {value}");
_isEntryEnabled = value;
gslEntry.IsEnabled = _isEntryEnabled;
SetBorderColor();
Debug.WriteLine("GEORGE: IsEntryEnabled Set End");
});
}
}
bool _isClearButtonVisible = false;
private bool IsClearButtonVisible
{
get
{
return _isClearButtonVisible;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
_isClearButtonVisible = value;
clearButton.IsVisible = _isClearButtonVisible;
});
}
}
private bool _isValid = true;
public bool IsValid
{
get
{
return _isValid;
}
set
{
Debug.WriteLine("GEORGE: IsValid Set Start");
_isValid = value;
invalidLabel.IsVisible = !_isValid;
SetBorderColor();
Debug.WriteLine("GEORGE: IsValid Set End");
}
}
private bool _isInFocus = false;
public bool IsInFocus
{
get
{
return _isInFocus;
}
set
{
Debug.WriteLine($"GEORGE: IsInFocus Set Start. Value: {value}");
_isInFocus = value;
Application.Current.Dispatcher.Dispatch(async () =>
{
if (_isInFocus)
{
var tempResult = gslEntry.Focus();
Debug.WriteLine($"GEORGE: Focus Result: {tempResult}");
}
else
{
gslEntry.Unfocus();
}
SetBorderColor();
Debug.WriteLine("GEORGE: IsInFocus Set End");
});
}
}
private void SetBorderColor()
{
Application.Current.Dispatcher.Dispatch(() =>
{
if (IsInFocus && IsEntryEnabled)
{
BorderColor = IsValid ? blue : red;
}
else
{
BorderColor = gray;
}
});
}
private Keyboard _keyboardMode = Keyboard.Plain;
public Keyboard KeyboardMode
{
get
{
return _keyboardMode;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
_keyboardMode = value;
gslEntry.Keyboard = _keyboardMode;
});
}
}
private KeyboardDisplayModeOptions _keyboardDisplayMode = KeyboardDisplayModeOptions.Always;
public KeyboardDisplayModeOptions KeyboardDisplayMode
{
get
{
return _keyboardDisplayMode;
}
set
{
_keyboardDisplayMode = value;
}
}
private int _maxLength = 0;
public int MaxLength
{
get
{
return _maxLength;
}
set
{
Application.Current.Dispatcher.Dispatch(() =>
{
_maxLength = value;
gslEntry.MaxLength = _maxLength;
});
}
}
//When entry is focused, change border color to blue
void Entry_Focused(object sender, FocusEventArgs e)
{
Debug.WriteLine("GEORGE: Entry_Focused start");
EntryFocused?.Invoke(sender, e);
Application.Current.Dispatcher.Dispatch(async () =>
{
Debug.WriteLine("GEORGE: ProcessKeyboard start");
Debug.WriteLine($"GEORGE IsInFocus: {IsInFocus}");
Debug.WriteLine($"GEORGE gslEntry.IsSoftKeyboardShowing(): {gslEntry.IsSoftKeyboardShowing()} ");
Debug.WriteLine($"GEORGE KeyboardDisplayMode: {KeyboardDisplayMode} ");
Debug.WriteLine($"GEORGE isFirstDisplay: {isFirstDisplay} ");
//Now set the keyboard accordingly.
if (KeyboardDisplayMode == KeyboardDisplayModeOptions.Always ||
(KeyboardDisplayMode == KeyboardDisplayModeOptions.AfterFirstEntry && !isFirstDisplay))
{
var result = await gslEntry.ShowSoftInputAsync(CancellationToken.None);
Debug.WriteLine($"GEORGE: Focus ShowKeyboard Result: {result}");
}
else
{
bool workResult = false;
//We know we are in the focus and the keyboard should come up. If we try to hide it and it fails keep trying - for up to 10 seconds - until it hides
workResult = await gslEntry.HideSoftInputAsync(CancellationToken.None);
Debug.WriteLine($"GEORGE: Focus HideKeyboard Result: {workResult}");
if (gslEntry.IsSoftKeyboardShowing())
{
isFirstDisplay = false;
}
}
Debug.WriteLine("GEORGE: ProcessKeyboard end");
});
SetBorderColor();
Debug.WriteLine("GEORGE: Entry_Focused end");
}
//When entry is not in focus, change border color to gray
void Entry_Unfocused(object sender, FocusEventArgs e)
{
Debug.WriteLine("GEORGE: Entry_UnFocused start");
clearButton.IsVisible = false;
EntryUnfocused?.Invoke(sender, e);
SetBorderColor();
Debug.WriteLine("GEORGE: Entry_UnFocused end");
}
//When entry is completed, run custom event
void Entry_Completed(object sender, EventArgs e)
{
EntryCompleted?.Invoke(sender, e);
}
public enum KeyboardDisplayModeOptions
{
Never = 0,
AfterFirstEntry = 1,
Always = 2
}
}
这是控件的 XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:GSL.Presentation.CustomControls"
xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="GSL.Presentation.CustomControls.GSLEntryControl"
x:DataType="controls:GSLEntryControl"
x:Name="customEntry">
<ContentView.Resources>
<ResourceDictionary>
<mct:InvertedBoolConverter x:Key="InvertedBoolConverter"/>
</ResourceDictionary>
</ContentView.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Border x:Name="entryFrame"
StrokeThickness="2"
Padding="0"
HeightRequest="50"
VerticalOptions="CenterAndExpand"
HorizontalOptions="FillAndExpand"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2">
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ColumnDefinitions="*,auto">
<Entry x:Name="gslEntry"
Margin="10,0,0,0"
ReturnType="Done"
Keyboard="Text"
TextTransform="Uppercase"
FontSize="16"
Completed="Entry_Completed"
Focused="Entry_Focused"
Unfocused="Entry_Unfocused"
Text="{Binding Text,Mode=TwoWay}"
IsEnabled="True"
Placeholder=""
IsPassword="False"
VerticalOptions="CenterAndExpand"
HorizontalOptions="FillAndExpand"
Grid.Column="0"/>
<!-- Clear Button -->
<ImageButton Source="ic_delete.xml"
x:Name="clearButton"
WidthRequest="32"
HeightRequest="32"
VerticalOptions="Center"
HorizontalOptions="End"
Margin="0,0,5,0"
Command="{Binding ClearTextCommand}"
Grid.Column="1"/>
</Grid>
</Border>
<Label x:Name="invalidLabel"
Text="{Binding ErrorText, Source={x:Reference customEntry}}"
Margin="5,0,0,0"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
IsVisible="false"
Style="{StaticResource ValidationErrorLabelStyle}"
Grid.Row="1"/>
</Grid>
</ContentView>
在 Entry 控件的 Entry_Focused 事件中 - 我尝试根据 KeyboardDisplayMode 的设置隐藏软键盘。 挑战在于应用程序似乎从未检测到键盘可见,因为 gslEntry.IsSoftKeyboardShowing() 始终返回 false。
这表明键盘可能在其他事件之后显示? 我只是想弄清楚在哪里放置我的代码,以便我可以隐藏软键盘。 条目控件曾经位于堆栈布局内,我读到条目与它配合得不好,所以我将所有内容都放在网格内。 不幸的是,这没有效果。
我还尝试从调度程序中删除异步,并完全删除调度程序的事件,但它们没有效果。
将以下内容添加到页面来测试自己
xmlns:controls="clr-namespace:GSL.Presentation.CustomControls"
<controls:GSLEntryControl x:Name="ULDIDInput" MaxLength="12" Text="" ErrorText="Bad Input"
IsInFocus="True" IsEntryEnabled="True" KeyboardDisplayMode="AfterFirstEntry"
EntryCompleted="ULDIDInput_EntryCompleted" IsValid="True" HorizontalOptions="EndAndExpand" WidthRequest="200"
PlaceholderText="Scan or Key Enter"/>
如有任何帮助,我们将不胜感激。
您可以使用处理程序来隐藏软键盘。
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
{
#if ANDROID
handler.PlatformView.ShowSoftInputOnFocus = false;
#endif
});