The event itself does not provide the possibility to change the user input as it is triggered after the text has already been changed.
This is far from being the ideal solution, I wouldn’t recommend it myself. But to make your code work would be 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 possibility to force capitalization.
See an example of it working on android and iOS:
MVVM - Using a ValueConverter
You would use that 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 Viewmodel to handle the data itself. You could declare it so:
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 captors in Viewmodel (Recommended).
In this case, the declaration of XAML
would be cleaner and decoupled (besides not needing the Valueconverter):
<SearchBar Text="{Binding SearchText}"
SearchCommand="{Binding SearchCommand}"/>
Your Viewmodel would treat the received data in calling the search command (i.e., in the method ExecuteSearch
) as you wish. In that case this part of the logic would be totally transparent to the user (and to the view) and its 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’ve helped.
Oh yes, sorry, I’m using like this:
<!-- Pesquisa -->
 <SearchBar x:Name="MainSearchBar"
 Placeholder="Digite o nome do produto..." 
 Margin="10, 12, 10, 0"
 BackgroundColor="LightGray"
 TextChanged="OnTextChanged"/>
– Deivid Souza