C# , UWP (TextBlock , Binding) - c#

How can I limit the number of characters in this TextBlock?
E.g.: It can only show up to 5 characters.
<TextBlock >
<Run Text="Tender Amount:"/>
<Run Text="{Binding TenderAmount,
Converter={StaticResource StringFormatConverter},
ConverterParameter='{}{0:C}'}" />
</TextBlock>
btw heres the Code in my Converter
public sealed class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format((string)parameter, value);
}
public object ConvertBack(object value, Type targetType, object parameter,
string language)
{
throw new NotImplementedException();
}
}
Thanks,
Nico

You can write your own Binding Converter to limit the number of displayed characters.
This one for example would simply limit the number of displayed characters to the first 5 characters in the string (or string representation of whatever you are passing into it).
public class StringLengthLimitConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
string val = value.ToString();
int length = parameter as int? ?? 5;
if (val.Length > length)
return val.Substring(0, length);
return val;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
Usage:
<Run Text="{Binding Path=TenderAmount,
Converter={StaticResource StringLengthLimitConverter},
ConverterParameter=5}" />
Depending on what you actually want to do, you might want to add an ellipsis (…) at the end.

You have to write your own converter like:
public class StringMaxLengthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
int MaxLength = Convert.ToInt32(parameter);
string TheString = (string)Value;
if (MaxLength > TheString.Length)
{
return TheString.SubString(0, MaxLength);
}
else
{
return TheString;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Declare it in your resources like:
<local:StringMaxLengthConverter x:Key="StrMaxLengthCvtr"/>
Use it in your TextBlock and pass the max string length like:
<TextBlock >
<Run Text="Tender Amount:"/>
<Run Text="{Binding TenderAmount, Converter={StaticResource StrMaxLengthCvtr}, ConverterParameter=5}" />
</TextBlock>

Related

Work with GridUnitType.Star in Grid column converter

I use a converter to fill the remaining space of a hidden column in WPF (set width to 0.0), but in fact I need the ratio 1.7* vs * if visible!
How can I calculate the real value to set for the converter?
Converter:
public class ColumnWidthConverter : IValueConverter
{
public object Convert(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
var isVisible = (bool) value;
var width = parameter as string == "*"
? new GridLength(1, GridUnitType.Star).Value
: double.Parse(parameter as string);
return isVisible ? width : 0.0;
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
}
As you can see I tried with new GridLength(1, GridUnitType.Star).Valuebut it's not the correct way!
XAML (condensed):
<appf:ViewUserControl.Resources>
<local:ColumnWidthConverter x:Key="ColumnWidthConverter" />
</appf:ViewUserControl.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.7*"/>
<ColumnDefinition Width="{Binding Path=Visible, Converter={StaticResource ColumnWidthConverter}, ConverterParameter=*}"/>
</Grid.ColumnDefinitions>
Visible is just a boolean property in the corresponding ViewModel!
Sometimes it's easy: use string instead of double value
public class ColumnWidthConverter : IValueConverter
{
public object Convert(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
var isVisible = (bool) value;
var width = parameter as string;
return isVisible ? width : "0.0";
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
}

Value converter fails on 2nd run but succeeds with try catch C#

I have a combo-box im populating with a collection of objects in my ViewModel.
<ComboBox x:Name="ChangelistComboBox"
SelectedIndex="{Binding MyObjectSelectionIndex, Mode=TwoWay}"
ItemsSource="{Binding MyObjectList, Mode=OneWay}"
Margin="5"
Grid.Column="0">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource MyObjectToComboBoxConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Im using a Converter to convert parameters from the object to a displaystring that shows up in the ComboBox
[ValueConversion(typeof(MyObject), typeof(string))]
class MyObjectToComboBoxConverter : ValueConverterBase
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
try {
MyObject theObject = (MyObject)value;
int id = theObject.Id;
return (((id != -1) ? id.ToString() : "default") + " : " + theObject.Description);
} catch(InvalidCastException e) {
return (String)value;
}
}
public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return new MyObject(); //Not used
}
}
abstract class ValueConverterBase : IValueConverter
{
public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return DependencyProperty.UnsetValue;
}
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return DependencyProperty.UnsetValue;
}
}
In the Model the list is defined as:
private ObservableCollection<MyObject> _MyObjectList;
public ObservableCollection<MyObject> MyObjectList {
get
{
if (_MyObjectList != null) { return _MyObjectList; } else { return new ObservableCollection<MyObject>(); }
}
set
{
if (_MyObjectList != value) {
_MyObjectList = value;
NotifyPropertyChanged("MyObjectList");
}
}
}
In the ViewModel the MyObjectList is simply referenced from the model through the interface:
public ObservableCollection<MyObject> MyObjectList {
get
{
if (Model != null) {
return Model.MyObjectList;
} else {
return new ObservableCollection<MyObject>();
}
}
}
Without the TryCatch, this converter crashes when my MyObjectList is updated. It gives an error like Cannot cast type string to object on the MyObject theObject = (MyObject)value; line
With the TryCatch the converter works as intended. It even returns a correctly assembled string. The problem is I get InvalidCastExceptions in the error log, which isnt good. Also I have no idea why it works despite the exception.
The only hunch I have is that for some reason the object is being converted twice, once from object to string and then it tries to convert the string to string and fails there. I cant figure out why it would be doing that though.
MVVM IValueConverter Convert method getting empty string argument when expecting a float
Just found this which seems to be the same issue that I'm experiencing. I dont fully understand the explanation for it given there, but if modifying the Convert to accept an empty string is a viable solution i can live with that
Still feels like a hack but beggars cant be choosers i guess
You bind the ComboBox source to a list of MyObject, so the value should never be of type string. I guess there is a problem in your model state.
The way you are binding your view is correct, also the first version of the converter:
[ValueConversion(typeof(MyObject), typeof(string))]
class MyObjectToComboBoxConverter : IValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
try {
var theObject = (MyObject)value;
var id = theObject.Id;
return (((id != -1) ? id.ToString() : "default") + " : " + theObject.Description);
} catch(InvalidCastException e) {
return (string)value;
}
}
public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
Please start to change your ViewModel to:
public ObservableCollection<MyObject> MyObjectList { get; set; } = new ObservableCollection<MyObject>();
You need to implement the OnPropertyChangeEvent on the properties of the MyObject model (https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-create-and-bind-to-an-observablecollection)
so you only need to set the ObservableCollection in your ViewModel to an empty instance by default.
Then adding items:
MyObjectList.Add(new MyObject{ id=1, Description="First"});

Doubles decimal separator WPF

Using a TextBox in WPF I have the problem that if I use ',' instead of '.' every time I try to get the value, the text inside the TextBox is transformed with the same number without comma..
How can I disable this automatic transformation?
<TextBox
x:Name="XValue"
Text="{Binding XInitValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="80" VerticalAlignment="Center"
TextChanged="XValue_TextChanged"
</TextBox>
private void XValue_TextChanged(object sender, TextChangedEventArgs e)
{
double a = XInitValue;
}
I solved it using an converter
public class DecimalConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == ".")
return value.ToString().Replace(",", ".");
else
return value.ToString().Replace(".", ",");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == ".")
return value.ToString().Replace(".", ",");
else
return value.ToString().Replace(",", ".");
}
}
It really works! Thanks!
I have change it a bit to be more general, not use the CurrentCulture in the converter itself and return error if the entered value is ended with decimal separator. Without last part I could not enter the decimal separator at all if the UpdateSourceTrigger=PropertyChanged.
public class DecimalConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return null;
}
if (value is string stringValue && targetType == typeof(decimal))
{
var decSeparator = culture.NumberFormat.NumberDecimalSeparator;
var normString = decSeparator == "."
? stringValue.Replace(",", ".")
: stringValue.Replace(".", ",");
if (!normString.EndsWith(decSeparator) && decimal.TryParse(normString, out var decResult))
{
return decResult;
}
}
return DependencyProperty.UnsetValue;
}
}
Certainly the CurrentCulture should be set in App.xml.cs or somewhere else on starting the application:
var culture = CultureInfo.GetCultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(culture.IetfLanguageTag)));

How to limit max char in ValueConverter

How can I limit the number of characters in this TextBlock?
E.g.: It can only show up to 5 characters.
<TextBlock >
<Run Text="Tender Amount:"/>
<Run Text="{Binding TenderAmount,
Converter={StaticResource StringFormatConverter},
ConverterParameter='{}{0:C}'}" />
</TextBlock>
Here's the Code in my Converter
public sealed class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format((string)parameter, value);
}
public object ConvertBack(object value, Type targetType, object parameter,
string language)
{
throw new NotImplementedException();
}
}
Use this:
public sealed class StringFormatConverter : IValueConverter
{
public int MaxLength { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return null;
if (parameter == null)
return value;
var result = string.Format((string)parameter, value);
if (MaxLength > 0)
result = result.Substring(0, MaxLength);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter,
string language)
{
throw new NotImplementedException();
}
}
Where you declare your converter resource, do this:
<stuff:StringFormatConverter x:Key="StringFormatConverter" MaxLength="5" />

System.Byte in datagrid column

I am using the following query:
string query = #"SELECT r.id, user_name, user_phone, date_create, REPLACE( date_payment, '0000-00-00 00:00:00', 'Не оплачено' ) as
date_payment, payment_method, amount, rs.name_ru
FROM request AS r, request_status AS rs
WHERE r.status = rs.id";
And i am binding datatemplate in the following way:
DataTemplate>
<TextBlock VerticalAlignment="Center" Text="{Binding date_payment}" Width="135" />
</DataTemplate>
Its throwing correct output except the "date_payment" Its output value comes "System.Byte[]".
please help!!!
Thank from MBen
class ByteArrayToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
var listOfBytes = value as Byte[];
string output = "";
output = System.Text.Encoding.UTF8.GetString(listOfBytes);
return output;
}
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
date_payment is an Array, and you didn't provide any way for WPF for displaying it, so it calls ToString . You can provide a data converter for it.
Add a resource to your Window or page :
<Window.Resources>
<local:ByteArrayToString x:Key="ByteArrayConverter" />
</Window.Resources>
Use it in your TextBlock as such :
<TextBlock VerticalAlignment="Center" Text="{Binding date_payement, Converter={StaticResource ByteArrayConverter}}" Width="135" />
Now you need to add a new class that does the conversion :
class ByteArrayToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
var listOfBytes = value as Byte[];
string output ="";
output = listOfBytes.Aggregate(output, (current, elemt) => current + elemt.ToString());
return output;
}
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
This thing happened to me to. It seems this is due to a bug in the connector. Try to cast the date column to CHAR. It worked for me.

Categories