Automatically capitalize all input in WPF - wpf

Is there a way to automatically capitalize all input throughout a WPF app?

You can case all input into TextBox controls with the following property:
CharacterCasing="Upper"
To apply to all TextBox controls in the entire application create a style for all TextBox controls:
<Style TargetType="{x:Type TextBox}">
<Setter Property="CharacterCasing" Value="Upper"/>
</Style>

If you want to capitalize the input for a single TextBox rather than all TextBoxes like above, you can use the following:
<TextBox CharacterCasing="Upper"/>

I recommend creating a custom Textbox class and override an event to automatically capitalize the text. First, this depends on if you want the text to be capitalize as they type or after input is finished.
E.g. for after input is finished
public class AutoCapizalizeTextBox: TextBox
{
public AutoCapitalizeTextBox()
{
}
public AutoCapitlizeTextBox()
{
}
protected override void OnLostFocus(EventArgs e)
{
this.Text = this.Text.ToUpper();
base.OnLostFocus(e);
}
}

I don't know if this'll help, it capitalizes all the first letters in the sentence.
http://www.mardymonkey.co.uk/blog/auto-capitalise-a-text-control-in-wpf/

Perhaps you can use a converter.
Here's the code of the converter:
using System;
using System.Globalization;
using System.Windows.Data;
namespace SistemaContable.GUI.WPF.Converters
{
public class CapitalizeFirstLetter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
string stringToTitleCase = culture.TextInfo.ToTitleCase(value.ToString());
return stringToTitleCase;
}
else
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString();
}
}
}
You need to reference it in a "ResourceDictionary" or in your "App.xaml":
<ResourceDictionary xmlns:converters="clr-namespace:SistemaContable.GUI.WPF.Converters">
<converters:CapitalizeFirstLetter x:Key="CapitalizeFirstLetter"/>
</ResourceDictionary>
And you can use it like this:
<TextBox x:Name="txtNombre" Text="{Binding Usuario.Nombre, Converter={StaticResource CapitalizeFirstLetter}, UpdateSourceTrigger=PropertyChanged}"/>

Related

How To Setup A Converter To Return Properties From Template

I'm making a style for a custom control that will can be one of two colors.
My properties of my control are: { SolidColorBrush color1, SolidColorBrush color2, bool usingColor1}.
I'm trying to make a converter that will bind to usingColor1 and will return either color1 or color2. I would like to define my converter like this:
<Style.Resources>
<Converters:ValueParameterComparisonConverter x:Key="Color1WhenTrue" ValueWhenEqual="{DataTemplateKey Color1}" ValueWhenNotEqual="{DataTemplateKey Color2}"/>
</Style.Resources>
And use my converter like this:
<Border Background="{TemplateBinding UsingColor1, Converter={StaticResource Color1WhenTrue}}" />
I have implemented this in my code and it does not work. I do not understand what DataTemplateKey does and do not think it is the correct word for this scenario.
How can I setup my converter to return properties from my template?
Edit:
Here is the interesting part of the converter code:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isEqual;
if (value == null)
{
isEqual = null == parameter;
}
else
{
isEqual = value.Equals(parameter);
}
return isEqual ? this.ValueWhenEqual : this.ValueWhenNotEqual;
}
You can get rid of the valueWhenEqual parameters;
<Style.Resources>
<Converters:ValueParameterComparisonConverter x:Key="Color1WhenTrue"/>
</Style.Resources>
Just use a binding rather than a templatebinding;
<Border Background="{Binding UsingColor1, Converter={StaticResource Color1WhenTrue}}" />
Then change your converter to return the color you want when true and another color when false;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var usingColor1 = (bool)value;
return usingColor1 ? new SolidColorBrush(Color.FromRgb(179, 255, 179)) : new SolidColorBrush(Color.FromRgb(255, 100, 0));
}
Obviously you'll need to change the colors used in the example I've given.

How can you get a XAML TextBlock in WP7 Silverlight to collapse when it contains no data?

I have a textblock inside a list view that I need to hide or collapse when it is empty or null. I tried using a string converter but that does not do it.
Any other ideas?
Update # 1:
Here is the code inside the textblock:
Visibility="{Binding Converter={StaticResource StringConverter}}
Here is the converter:
public class StringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
return string.IsNullOrEmpty(value.ToString()) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
I would recommend creating text and visibility bindings on your textbox.
Here's an example of the view model properties you'd have.
public String TextBoxText
{
get { return textBoxText; }
set
{
if (value != textBoxText)
{
textBoxText= value;
SetTextBoxVisibility();
OnPropertyChanged("TextBoxText");
}
}
}
private String textBoxText;
public Visibility TextBoxVisibility
{
get { return textBoxVisibility; }
set
{
if (value != textBoxVisibility)
{
textBoxVisibility= value;
OnPropertyChanged("TextBoxVisibility");
}
}
}
private Visibility textBoxVisibility;
public void SetTextBoxVisibility()
{
this.TextBoxVisibility = String.IsNullOrEmpty(this.TextBoxText) ? Visibility.Collapsed : Visibility.Visible;
}
The only thing you've not shown of your code is where you instantiate the converter class. Is this because you're not doing so?
Typically you'd add something like this to app.xaml:
<Application.Resources>
<ResourceDictionary>
<conv:StringConverter x:Key="StringConverter " />
</ResourceDictionary>
</Application.Resources>

Automatically capitalize first letter in TextBoxes

I am creating a wpf application. I have to make all textbox first letter to capital, if a user entered in small then it should be formatted in capital on mouse out.I need the best way to do it, please someone help me.
The best way of doing it greatly depends on how you are doing your app, but #H.B.'s answer is probably the way to go.
For the sake of completeness, another way if doing it would be to use a converter like so:
<!-- Your_Window.xaml -->
<Window x:Class="..."
...
xmlns:cnv="clr-namespace:YourApp.Converters">
<Window.Resources>
<cnv.CapitalizeFirstLetterConverter x:Key="capFirst" />
</Window.Resources>
...
<TextBox Text="{Binding Path=SomeProperty, Converter={StaticResource capFirst}}" />
This assumes that your window's data context is set to an instance of a class that has a read/write property named SomeProperty of type string.
The converter itself would be something like this:
// CapitalizeFirstLetterConverter.cs
using System;
using System.Data;
using System.Globalization;
namespace YourApp.Converters {
[ValueConversion(typeof(string), typeof(string))]
public class CapitalizeFirstLetterConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
// this will be called after getting the value from your backing property
// and before displaying it in the textbox, so we just pass it as-is
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
// this will be called after the textbox loses focus (in this case) and
// before its value is passed to the property setter, so we make our
// change here
if (value is string) {
var castValue = (string)value;
return char.ToUpper(castValue[0]) + castValue.Substring(1);
}
else {
return value;
}
}
}
}
You can learn more about converters here.
You could put a style into the Application.Resources to handle LostFocus on all TextBoxes, then you just need to change the Text property accordingly.
<!-- App.xaml - Application.Resources -->
<Style TargetType="{x:Type TextBox}">
<EventSetter Event="LostFocus" Handler="TextBox_LostFocus" />
</Style>
// App.xaml.cs - App
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var tb = (TextBox)sender;
if (tb.Text.Length > 0)
{
tb.Text = Char.ToUpper(tb.Text[0]) + tb.Text.Substring(1);
}
}
I'm a bit late to the game, but if anybody else needs it this dll capitalizes the first letter in realtime. For example, you don't need to mouse out.
http://www.mardymonkey.co.uk/blog/auto-capitalise-a-text-control-in-wpf/
Perhaps you can use a converter but not a converter like #ssarabando, because it is bugged.
Here's the code of the converter:
using System;
using System.Globalization;
using System.Windows.Data;
namespace SistemaContable.GUI.WPF.Converters
{
public class CapitalizeFirstLetter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
string stringToTitleCase = culture.TextInfo.ToTitleCase(value.ToString());
return stringToTitleCase;
}
else
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString();
}
}
}
You need to reference it in a "ResourceDictionary" or in your "App.xaml":
<ResourceDictionary xmlns:converters="clr-namespace:SistemaContable.GUI.WPF.Converters">
<converters:CapitalizeFirstLetter x:Key="CapitalizeFirstLetter"/>
</ResourceDictionary>
And you can use it like this:
<TextBox x:Name="txtNombre" Text="{Binding Usuario.Nombre, Converter={StaticResource CapitalizeFirstLetter}, UpdateSourceTrigger=PropertyChanged}"/>

WPF databinding binding error notification

OK, working on WPF(using MVVM) and came across a question, want some input. I have a simple class
like below(assume I have IDataErrorInfo implemented):
public class SimpleClassViewModel
{
DataModel Model {get;set;}
public int Fee {get { return Model.Fee;} set { Model.Fee = value;}}
}
I then try to bind to it in xaml:
<TextBox Text={Binding Fee, ValidatesOnDataErrors=true}/>
when a user then clears out the text, a databinding error occurs because it cant convert string.empty to int. Well, Fee is a required field, but because the databinding won't convert back I can't provide error information because my class isn't updated. So am I required to then do the following?
public class SimpleClassViewModel
{
DataModel Model {get;set;}
int? _Fee;
public int? Fee
{
get { return _Fee;}
set { _Fee = value;if (value.HasValue) { Model.Fee = value;}
}
}
This can be done using a ValueConverter:
using System.Windows.Data;
namespace MyNameSpace
{
class IntToStringConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((int) value).ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
int result;
var succes = int.TryParse((string) value,out result);
return succes ? result : 0;
}
}
}
You reference it in the XAML thus:
<Window xmlns:local="clr-namespace:MyNameSpace">
<Window.Resources>
<local:IntToStringConverter x:Key="IntConverter"/>
</Window.Resources>
<TextBox Text={Binding Fee, ValidatesOnDataErrors=true,
Converter={StaticResource IntConverter}}/>
</Window>
You can also take advantage of the fact you're doing MVVM and change the type of the Fee property to string. After all, your VM should provide a model that supports the view, and the view allows users to enter a string. Then you can provide a separate property that exposes the parsed fee as an int. That way your conversion logic is right there in the Fee property, making it easier to reuse, debug, and maintain.

WPF binding ComboBox to enum (with a twist)

Well the problem is that I have this enum, BUT I don't want the combobox to show the values of the enum. This is the enum:
public enum Mode
{
[Description("Display active only")]
Active,
[Description("Display selected only")]
Selected,
[Description("Display active and selected")]
ActiveAndSelected
}
So in the ComboBox instead of displaying Active, Selected or ActiveAndSelected, I want to display the DescriptionProperty for each value of the enum. I do have an extension method called GetDescription() for the enum:
public static string GetDescription(this Enum enumObj)
{
FieldInfo fieldInfo =
enumObj.GetType().GetField(enumObj.ToString());
object[] attribArray = fieldInfo.GetCustomAttributes(false);
if (attribArray.Length == 0)
{
return enumObj.ToString();
}
else
{
DescriptionAttribute attrib =
attribArray[0] as DescriptionAttribute;
return attrib.Description;
}
}
So is there a way I can bind the enum to the ComboBox AND show it's content with the GetDescription extension method?
Thanks!
I would suggest a DataTemplate and a ValueConverter. That will let you customize the way it's displayed, but you would still be able to read the combobox's SelectedItem property and get the actual enum value.
ValueConverters require a lot of boilerplate code, but there's nothing too complicated here. First you create the ValueConverter class:
public class ModeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
return ((Mode) value).GetDescription();
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotSupportedException();
}
}
Since you're only converting enum values to strings (for display), you don't need ConvertBack -- that's just for two-way binding scenarios.
Then you put an instance of the ValueConverter into your resources, with something like this:
<Window ... xmlns:WpfApplication1="clr-namespace:WpfApplication1">
<Window.Resources>
<WpfApplication1:ModeConverter x:Key="modeConverter"/>
</Window.Resources>
....
</Window>
Then you're ready to give the ComboBox a DisplayTemplate that formats its items using the ModeConverter:
<ComboBox Name="comboBox" ...>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource modeConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
To test this, I threw in a Label too, that would show me the actual SelectedItem value, and it did indeed show that SelectedItem is the enum instead of the display text, which is what I would want:
<Label Content="{Binding ElementName=comboBox, Path=SelectedItem}"/>
I like the way you think. But GetCustomAttributes uses reflection. What is that going to do to your performance?
Check out this post:
WPF - Displaying enums in ComboBox control
http://www.infosysblogs.com/microsoft/2008/09/wpf_displaying_enums_in_combob.html
This is how I am doing it with MVVM. On my model I would have defined my enum:
public enum VelocityUnitOfMeasure
{
[Description("Miles per Hour")]
MilesPerHour,
[Description("Kilometers per Hour")]
KilometersPerHour
}
On my ViewModel I expose a property that provides possible selections as string as well as a property to get/set the model's value. This is useful if we don't want to use every enum value in the type:
//UI Helper
public IEnumerable<string> VelocityUnitOfMeasureSelections
{
get
{
var units = new []
{
VelocityUnitOfMeasure.MilesPerHour.Description(),
VelocityUnitOfMeasure.KilometersPerHour.Description()
};
return units;
}
}
//VM property
public VelocityUnitOfMeasure UnitOfMeasure
{
get { return model.UnitOfMeasure; }
set { model.UnitOfMeasure = value; }
}
Furthermore, I use a generic EnumDescriptionCoverter:
public class EnumDescriptionConverter : IValueConverter
{
//From Binding Source
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is Enum)) throw new ArgumentException("Value is not an Enum");
return (value as Enum).Description();
}
//From Binding Target
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is string)) throw new ArgumentException("Value is not a string");
foreach(var item in Enum.GetValues(targetType))
{
var asString = (item as Enum).Description();
if (asString == (string) value)
{
return item;
}
}
throw new ArgumentException("Unable to match string to Enum description");
}
}
And finally, with the view I can do the following:
<Window.Resources>
<ValueConverters:EnumDescriptionConverter x:Key="enumDescriptionConverter" />
</Window.Resources>
...
<ComboBox SelectedItem="{Binding UnitOfMeasure, Converter={StaticResource enumDescriptionConverter}}"
ItemsSource="{Binding VelocityUnitOfMeasureSelections, Mode=OneWay}" />
I suggest you use a markup extension I had already posted here, with just a little modification :
[MarkupExtensionReturnType(typeof(IEnumerable))]
public class EnumValuesExtension : MarkupExtension
{
public EnumValuesExtension()
{
}
public EnumValuesExtension(Type enumType)
{
this.EnumType = enumType;
}
[ConstructorArgument("enumType")]
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (this.EnumType == null)
throw new ArgumentException("The enum type is not set");
return Enum.GetValues(this.EnumType).Select(o => GetDescription(o));
}
}
You can then use it like that :
<ComboBox ItemsSource="{local:EnumValues local:Mode}"/>
EDIT: the method I suggested will bind to a list of string, which is not desirable since we want the SelectedItem to be of type Mode. It would be better to remove the .Select(...) part, and use a binding with a custom converter in the ItemTemplate.
Questions of using reflection and attributes aside, there are a few ways you could do this, but I think the best way is to just create a little view model class that wraps the enumeration value:
public class ModeViewModel : ViewModel
{
private readonly Mode _mode;
public ModeViewModel(Mode mode)
{
...
}
public Mode Mode
{
get { ... }
}
public string Description
{
get { return _mode.GetDescription(); }
}
}
Alternatively, you could look into using ObjectDataProvider.
I've done it like this :
<ComboBox x:Name="CurrencyCodeComboBox" Grid.Column="4" DisplayMemberPath="." HorizontalAlignment="Left" Height="22" Margin="11,6.2,0,10.2" VerticalAlignment="Center" Width="81" Grid.Row="1" SelectedValue="{Binding currencyCode}" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
in code I set itemSource :
CurrencyCodeComboBox.ItemsSource = [Enum].GetValues(GetType(currencyCode))

Resources