I know that you can limit the input characters of TextBox from user by setting MaxLength property.
Is there a similar way to limit the number of characters shown in Text when the Text is updated with Binding? For example, when it is updated from Binding just show the first 5 characters and leave the rest?
Update:
Thanks for all the info, I got inspired by your recommendation and in the end did it with a converter. Here is how I did it, if someone wants to use it later.
public class StringLimiter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string val = value.ToString();
if (val.Length < 5)
return val;
else
return val.Substring(0, 5);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string val = value.ToString();
if (val.Length < 5)
return val;
else
return val.Substring(0, 5);
}
}
This should work:
Xaml:
<TextBox Text="{Binding TextToDisplay}" />
Code:
private const int maxLength = 5;
private string _textToDisplay = "Hello SO";
public string TextToDisplay
{
get
{
if(_textToDisplay.Length > maxLength)
{
return _textToDisplay.Substring(0, maxLength);
}
return _textToDisplay;
}
set
{
_textToDisplay = value;
RaiseProperyChanged();
}
}
I hope to understand you right. You could create a new Property in the ViewModel that returns only the first 5 chars of the text and set your binding to that property.
You might need to call PropertyChanged for the new Property when the text changes.
A simple but very flexible way of doing it would be to introduce a projected property in your Viewmodel that returns the first 5 characters of the original property and then bind your control to this property. Since you're only showing part of the property value, I assume that you don't want to write to this property from that TextBox. So make you projected property read-only too.
Related
I'm creating weather app with forecast. I have created ListView with TextCell as entries.
I want to format test inside cell to XXX YY where:
XXX is value
YY is unit
I have observable collection declared in ContentPage and it is my ItemSource, I have another important property, weatherUnit.
private ObservableCollection<ForecastData> forecast = new ObservableCollection<ForecastData>();
private Unit weatherUnit { get; set; }
I'm creating Data template in constructor and setting everything up:
public WeatherFormsAppPage()
{
InitializeComponent();
var forecastWeatherDataTemplate = new DataTemplate(typeof(TextCell));
forecastWeatherDataTemplate.SetBinding(TextCell.TextProperty, "mainData.Temperature");
forecastWeatherDataTemplate.SetBinding(TextCell.DetailProperty, "date");
ForecastView.ItemsSource = forecast;
ForecastView.ItemTemplate = forecastWeatherDataTemplate;
}
How I can add to TextCell.TextProperty binding formatting to be temperature and weatherUnit. Temperature is double and weather unit have Extension that return String. Right now, only Temperature value is shown properly and date as detail:
You can create a readonly property that concats the values for you and then bind to that
public string WeatherData
{
get
{
return $"{Temperature} {Unit}";
}
}
binding
forecastWeatherDataTemplate.SetBinding(TextCell.TextProperty, "mainData.WeatherData ");
I also like David's approach. Having a get-only property in your JSON class is nothing to worry about. As you don't want to go that way, you can also write a converter class and add that to your binding.
public class StringToFormattedTempConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is string))
return value;
return $"{(string)value} \u00B0CC";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then add it to the binding like this.
forecastWeatherDataTemplate.SetBinding(TextCell.TextProperty, new Binding("mainData.Temperature", BindingMode.Default, new StringToFormattedTempConverter(), null));
I am working on a WPF app. In this app, I have some XAML segments. I need to display the XAML segments in a TextBlock. In my XAML, I have the following line:
<TextBlock Text="{Binding Path=XamlSegment, Converter={StaticResource XamlToTextConverter}}" />
The XamlSegment property will have a value like "-0.275*x2". In an attempt to render this XAML in my UI so that the Superscript shows, I'm using the XamlToTextConverter, which is defined as follows:
namespace MyApp.Converters
{
public class XamlToTextConverter : IValueConverter
{
private static readonly Regex Regex = new Regex("(<.*?)>(.*)(</.*?>)", RegexOptions.Compiled);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// value looks like this: -0.275*x<Run Typography.Variants="Superscript">2</Run>
var xamlText = value as string;
if (xamlText != null)
{
try
{
xamlText = "<TextBlock>" + xamlText + "</TextBlock>";
var xamlTextWithNamespace = Regex.Replace(xamlText, "$1 xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">$2$3");
return XamlReader.Parse(xamlTextWithNamespace);
}
catch (Exception)
{
return value;
}
}
else
{
return value;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
When this converter gets ran, my UI shows "System.Windows.Controls.TextBlock" instead of the rendered XAML. Yet, I don't know why. How do I get my XamlSegment to render in my UI?
Thanks
The Text property of the TextBlock will be set to a TextBlock object according to your XamlToTextConverter. Since the Text property should be type of string, it doesn't know how to show a TextBlock as string. So the default way to get thing done is to use the ToString method on TextBlock to fill the Text property, which makes the value of Text as "System.Windows.Controls.TextBlock".
It seems that you would like to dynamically render the xaml. You could reference this link(Loading XAML XML through runtime?) for a solution.
I am just learning Datagrids and had a question I could not find a clear answer to.
How would I be able to manipulate a bound string to replace everything before the last / and add then a different prefix.
This will be to show an image in a Datagrid.
For example what is bound to img variable is
img: "/img_banner/testBanner.jpg"
What finally needs to be output is this:
http://www.testsite.com/img_thumnail/testBanner.jpg
So far, I have found information about adding text to a bound string but I would like to remove part of the String.
Here is what I got so far:
<Image Source="{Binding img, StringFormat=http://www.testsite.com/img_thumnail{0}}" Height="40"/>
Is there any way to easily trim everything before the last / ?
You can use an IValueConverter:
public class MyUrlConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null)
{
return null;
}
var urlString = value as string;
//now do whatever you want to do with the string
//then return it
return urlString;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
then add it to your resources
<Window.Resources>
<local:MyUrlConverter x:Key="conv"></local:MyUrlConverter>
</Window.Resources>
and use it as:
<Image Source="{Binding img,Converter={StaticResource ResourceKey=conv}}"></Image>
note that if the logic dependant on your view model then you better do your thing in the getter or the setter of your img property
I have a question here to ask. I have an enum which at runtime shows in the UI. It has three values.
enum ExpiryOptions
{
Never,
After,
On
}
Now from the userControl when it loads its shows Never, After, on.
<ComboBox x:Name="accessCombo" Margin="5" Height="25" Width="80"
ItemsSource="{Binding Source={StaticResource ResourceKey=expiryEnum},
Converter={StaticResource enumtoLocalizeConverter}}"/>
In English its fine but the problem is, if the software is used as a localized settings the same strings appear. And not any localized strings.
In the converter I have a written a code like this
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
ExpiryOption[] myEnum = value; // This myEnum is having all the enum options.
// Now what shall I write here
//if I write a code like this
if(myEnum[0] == Properties.Resources.Never)
return Properties.Resources.Never;
else if(myEnum[1] == Properties.Resources.After)
return Properties.Resources.After;
else if(myEnum[2] == Properties.Resources.On)
return Properties.Resources.On;
}
then the enum in the UI fills with N E V E R (vertically) In English Language settings. Obviously the first string matches and fills with Never other two options are missing. Any suggestions and help is extremely needed.
You are always returning first enum value from converter i.e. string value Never which is char array hence you are seeing one item as single char in your comboBox.
Instead you should return string list:
List<string> descriptions = new List<string>();
foreach(ExpiryOption option in myEnum)
{
if(option == Properties.Resources.Never)
descriptions.Add(Properties.Resources.Never);
else if(option == Properties.Resources.After)
descriptions.Add(Properties.Resources.After);
else if(option == Properties.Resources.On)
descriptions.Add(Properties.Resources.On);
}
return descriptions;
You need to get the value passed into the ValueConverter to use it as follows.
[ValueConversion(typeof(ExpiryOptions), typeof(string))]
public class MyEnumConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ExpiryOptions option=
(ExpiryOptions)Enum.Parse(typeof(ExpiryOptions),value.ToString());
// Now that you have the value of the option you can use the culture info
// to change the value as you wish and return the changed value.
return option.ToString();
}
}
Assuming you have defined resources strings for Never, After, On as strings in class Properties as ExpiryOptionsNever, ExpiryOptionsAfter, ExpiryOptionsOn respectively(of course with strings you need) I would write this converter:
public class EnumConverter: IValueConverter{
public Dictionary<ExpiryOptions, string> localizedValues = new Dictionary<ExpiryOptions, string>();
public EnumConverter(){
foreach(ExpiryOptionsvalue in Enum.GetValues(typeof(ExpiryOptions)))
{
var localizedResources = typeof(Resources).GetProperties(BindingFlags.Static).Where(p=>p.Name.StartsWith("ExpiryOptions"));
string localizedString = localizedResources.Single(p=>p.Name="ExpiryOptions"+value).GetValue(null, null) as string;
localizedValues.Add(value, localizedString);
}
}
public void Convert(...){
return localizedValues[(ExpiryOptions)value];
}
}
This is essentially what user Blam suggested in the comments
I've bound my TextBox to a string value via
Text="{Binding AgeText, Mode=TwoWay}"
How can I display string.empty or "" for the string "0", and all other strings with their original value?
Thanks for any help!
Cheers
PS: One way would be a custom ViewModel for the string.. but I'd prefer to do it somehow in the XAML directly, if it's possible.
I think the only way beside using the ViewModel is creating a custom ValueConverter.
So basically your choices are:
ViewModel:
private string ageText;
public string AgeText{
get{
if(ageText.equals("0"))
return string.empty;
return ageText;
}
...
}
ValueConverter:
public class AgeTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.Equals("0"))
return string.Empty;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
}
}
I found something on http://www.codeproject.com/KB/books/0735616485.aspx
This will do the trick:
Text="{Binding AgeText, StringFormat='\{0:#0;(#0); }'}"
Cheers
Since the Age property is obviously a number here, an other way to go would be to expose the Age as an int and use the StringFormat attribute of the Binding:
Text="{Binding Age, Mode=TwoWay, StringFormat='{}{0:#}'}"