The event itself does not provide the ability to change user input, as it is triggered after the text has already been changed.
This is far from the ideal solution, I particularly would not recommend, inclusive. But to make your code work it would look like this:
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
if(!string.IsNullOrWhiteSpace(e.NewTextValue))
((SearchBar)sender).Text = e.NewTextValue.ToUpper();
}
Alternatives
Use a component that handles data entry
GitHub has the 'CapitalizeKeyboard' component, for example . It provides the ability to force entry into uppercase.
See an example of it working on android and iOS:
MVVM - Using ValueConverter
You would use this Converter
:
public class CapitalizeTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Capitalize(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Capitalize(value);
}
private object Capitalize(object value)
{
if (value == null || !(value is string) || string.IsNullOrWhiteSpace(value))
return value;
return value.ToString().ToUpper();
}
}
In this case, your statement in XAML
would look like this:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converter="clr-namespace:App.Converters"
xmlns:viewModel="clr-namespace:App.ViewModels"
x:Class="App.Views.SettingsPage">
<ContentPage.Resources>
<ResourceDictionary>
<converter:CapitalizeTextConverter x:Key="CapitalizeTextConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.BindingContext>
<viewModel:MyViewModel/>
</ContentPage.BindingContext>
<StackLayout>
...
<SearchBar Text="{Binding SearchText, Converter={StaticResource CapitalizeTextConverter}}"
SearchCommand="{Binding SearchCommand}"/>
...
</StackLayout>
</ContentPage>
You would need the ViewModel to handle the data itself. You could declare it like this:
public class MyViewModel : INotifyPropertyChanged
{
private string searchText;
public string SearchText
{
get{ return searchText; }
set
{
if(value != searchText)
{
searchText = value;
OnPropertyChanged("SearchText");
}
}
}
public Command SearchCommand { get; set; }
public MyViewModel()
{
SearchCommand = new Command(ExecuteSearch);
}
private void ExecuteSearch()
{
// Aqui você faria a lógica da busca como desejasse.
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
MVVM - Using bindings and handling the captlers in the ViewModel (Recommended).
In this case, the searchbar declaration in XAML
would be cleaner and decoupled (in addition to not needing ValueConverter ):
<SearchBar Text="{Binding SearchText}"
SearchCommand="{Binding SearchCommand}"/>
Your ViewModel would treat the data received in the invocation of the search command (that is, in the ExecuteSearch
method) as you wish. In that case this part of the logic would be totally transparent to the user (and to the view) and his business rule would be 'testable':
private void ExecuteSearch()
{
var texto = SearchText?.ToUpper();
if(!string.IsNullOrWhiteSpace(texto))
{
// Aqui você faria a busca como desejasse.
}
}
I hope I have helped.