update TextBox text format on LostFocus - WinRT - c#

I am developing an Windows Store app using C# and XAML and am working on a user input page. I use an IValueConverter that converts my bound data into currency formatted string instead of just showing a decimal.
When the user navigates to the page, the converter works fine and the TextBox text shows up with a currency format. However, when the user changes the TextBox.Text value and then the TextBox loses focus, the converter does not change it into a nice currency format again, it just stays formatted as it was entered by the user.
As far as I can tell, there is no StringFormat to use like in WPF, so how do I get the TextBox to display the currency format again after the user edits the value?
My converter:
public object Convert(object value, Type targetType, object parameter, string language)
{
if (parameter == null)
return ((decimal)value).ToString();
return String.Format((string)parameter, (decimal)value);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
decimal decVal = 0M;
decimal.TryParse((string)value, out decVal);
return decVal;
}
My XAML:
<Grid x:Name="InputGrid">
...
<Border>
<TextBox Text="{Binding MyValue, ConverterParameter='{}{0:c}', Converter={StaticResource DecimalValueConverter}, Mode=TwoWay}"
</Border>
....
</Grid>
InputGrid.DataContext = MyValueClassInstance set in the code-behind

Does your converter work both ways? I suspect that if it doesn't - the TwoWay binding gets broken.

What if you do this:
<TextBox Text="{Binding MyValue, UpdateSourceTrigger=PropertyChanged, ConverterParameter='{}{0:c}', Converter={StaticResource DecimalValueConverter}, Mode=TwoWay}"

Related

FFImageLoading has wrong behavior when resource is not found (issue or PEBKAC ?)

I use FFImageLoading to show SVG images in a ListView like this :
1) I have an XML file with categories and items, I parse it, I have an ObservableCollection, each Category is an ObservableCollection.
2) I have a custom TintedSvgCachedImage class which inherits from SvgCachedImage (just adding some tint color on a bindable property) ; I bind the Source property to a a Category.Label property, and use a converter to return an SvgImageSource.
3) If the corresponding embedded resource is not found, I catch the Exception and I return another image.
This works very well when the image is found. When not, I face 2 issues :
1) If it is the last Category in the ListView, no Exception is thrown and the images is just "empty", nothing is displayed, without any error
2) If it is not the last Category, an Exception is thrown as expected, but the replacing image is not the one I wanted to load !
My XAML file :
<ListView.GroupHeaderTemplate>
<DataTemplate x:DataType="models:Category">
<ViewCell Height="50">
<StackLayout Orientation="Horizontal">
<ffsvgimg:TintedSvgCachedImage Source="{Binding Label, Converter={StaticResource CategoryNameToSvgImageResource}}"
TintColor="Accent" />
<Label Text="{Binding Name, Converter={StaticResource StringCaseConverter}, ConverterParameter=U}"
Padding="15, 0" VerticalOptions="CenterAndExpand"
FontSize="12" FontAttributes="Bold" Opacity="0.75" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
And the converter :
// Convert Category Name (or Label) to SVG image resource to be displayed in ListView
public class CategoryNameToSvgImageResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType() != typeof(string))
throw new FormatException("CategoryNameToSvgImageResource: argument value is not of type String.");
try
{
return SvgImageSource.FromResource("CardioCALC.Resources." + value.ToString() + ".svg");
}
catch (Exception)
{
return SvgImageSource.FromResource("CardioCALC.Resources.HeartFailure.svg");
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Does the problem come from me ? Missing something ?
Or do I have to open an issue on GitHub ? (I did not find any, but I did not search a lot as I am not sure the problem is not my bad...)
Thanks,
Olivier

Formatting a bound property

I want to bind Value of a Slider to a Content of a Label. The value of the slider sets a timespan. The value of the slider is a timespan in minutes (value 5 = 5 minutes).
This is my XAML for the Label:
<Label
Content="{Binding Value, ElementName=sld_Timespan}"
ContentStringFormat="{}{0:HH:mm}"
/>
I can bind them. The values are correct. But the format is wrong.
For ContentStringFormat i tried different settings, like on this (TextBlock in Silverlight) or this (TextBlock Multibinding) site. I also took the data binding dialog and set the StringFormat to {0:G} (you can choose this from a ComboBox) or other settings.
I only get a value "formatted" as double, like "1" or "13.423523423".
I also tried TextBlock. The same problem.
What is wrong with my XAML code?
After the comment of Clemens i understood what was wrong. I wrote a simple Converter:
public class DoubleToTimespanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return TimeSpan.FromMinutes((double)value).ToString(#"hh\:mm\:ss");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And added to my XAML:
<UserControl.Resources>
<!--local is my local namespace-->
<local:DoubleToTimespanConverter x:Key="converter"/>
</UserControl.Resources>
And i could easily set "converter" as my converter.

How to make IValueConverter return text with different fontsizes, superscripts and/or subscripts

Can anyone please let me know how I could make a Converter return text with varying font-sizes, so that the bound textblock can display it? If this is not possible with a TextBlock, I can use alternative element as well.
Here is the code that I have right now, this obviously doesn't work
In my XAML file:
<TextBlock Text="{Binding Converter={StaticResource LabelFormatConerter}}"/>
In my XAML.cs file:
public class LabelFormatConerter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TextBlock tb = new TextBlock();
Run runLargeFont = new Run();
runLargeFont.FontSize = 18;
runLargeFont.Text = "Larger Font Text";
tb.Inlines.Add(runBase);
Run runSmallFont = new Run();
runSmallFont.FontSize = 8;
runSmallFont.BaselineAlignment = BaselineAlignment.Superscript;
runSmallFont.Text = "Smaller Font Text";
tb.Inlines.Add(runSmallFont);
return tb.Text;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
This should work for you:
<TextBlock FontFamily="Calibri">
<Run>Normal Text</Run>
<Run Typography.Variants="Superscript">Test</Run>
<Run Typography.Variants="Subscript">7</Run>
</TextBlock>
Not all fonts support super\subscripts, so I had to specify it explictly.
What will be your input? Two/three separate values, or one value that you need to split into a normal value, superscript and subscript?
This might be possible to do with a TextBlock but I don't know how. Your converter returns a collection of Run objects, while the Text property expects a string.
An alternative is to user an items control:
<ItemsControl ItemsSource="{Binding Converter={StaticResource LabelFormatConerter}}" />
and return
tb.Inlines
from your converter. (ideally you just create just a collection inside your converter, not a new TextBlock)
A converter is not the right tool for this job - this is what ContentTemplate is there for. Simply use a ContentControl, bind the data to the Content property and display the data however your want to in your ContentTemplate:
<ContentControl Content="{Binding Person}">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock>
<Run FontSize="18" Text="{Binding FirstName}" />
<Run FontSize="8" Text="{Binding LastName}" />
</TextBlock>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>

Dynamic custom content in RichTextBox

I wish to display a text + hyperlinks in a RichTextBox from the code-behind or the binded via the Xaml if there is the possibility.
For the moment, I have a string variable with a Url (that I'd like very much to make clickable) binded to a TextBlock. I'd like to basically replace:
<TextBlock Text="{Binding myTextWithUrl}" />
by (in a richTB: )
<Run Text="partOfTextNonUrl" /><Hyperlink NavigateUri="theUrl" TargetName="whatever" />
Here is how it is presented:
I have an ItemsControl templated with a custom object
<ItemsControl ItemsSource="{Binding FeedResults}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" >
<my:SearchResultItem />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And this custom control presents the binded data in 3 TextBlocks as presented above: title, date, and the text containing text + urls.
I have already a method that extracts the urls from the string, I just don't know how to use it. I can generate dynamically Run() and Hyperlink(), and add them to the paragraph, but how to bind ?
Or any other solution ? You'd make my day!!
Thanks, Sylvain
OK. So apparently inline Hyperlinks aren't even allowed in Silverlight. But you can make your own!
http://csharperimage.jeremylikness.com/2009/11/inline-hyperlinks-in-silverlight-3.html
Not easy - at least not as easy at it should be. But it should get the job done.
Once you have the ability to add these runs with hyperlinks, the way I'd approach it is this. Create a user control with a single TextBlock (txtContent). Set the DataContext="{Binding myTextWithUrl}". Then in the code behind:
public TextWithUrlUserControl()
{
InitializeComponent();
this.Loaded += (s, e) =>
{
foreach(var inline in ParseText(DataContext as string))
txtContent.Inlines.Add(inline);
};
}
IEnumerable<Inline> ParseText(string text)
{
// return list of Runs and Runs with hyperlinks using your URL parsing
// for demo purposes, just hardcoding it here:
return new List<Inline>
{
new Run{Text="This text has a "},
new Run{Text="URL", RunExtender.NavigateUrl="http://www.google.com/"},
new Run{Text="in it!"}
};
}
Hope this is helpful.
I would do something like this. Create a ValueConverter which will take your text (with the URL in it). Then in your TextBlock, create the Run and Hyperlink - bind both to the text, both using the ValueConverter, but with a different parameter to the ValueConverter.
The ValueConverter:
public class MyCustomValueConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(parameter.ToString()== "URL")
{
// return the URL part of the string
}
else
{
// return the non-URL portion of the string
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then your XAML looks like this:
<Run Text="{Binding myTextWithUrl, Converter={StaticResource valueConverter}}"></Run><Hyperlink NavigateUri="{Binding myTextWithUrl, Converter={StaticResource valueConverter}, ConverterParameter=URL}"></Hyperlink>

Set a default name to a combobox in WPF

I have a combobox filled with int's representing years. The years I have add them to an ObservableCollection, but my problem is when I load the project the combobox its blank by default. I want to set a default name to it, like "Years", but I don't want solution like set the isEditable to true, or inserting a string at the beginning. I want a pure xaml solution if it is posible.
This is my current xaml file:
<RSControls:SmoothScrollComboBox Grid.Column="1" x:Name="compilationYearCombo" Margin="7,2.04,0,2.04"
SelectedValue="{Binding Path=SelectedYear}"
SelectedValuePath=""
ItemsSource="{Binding Years}"
DisplayMemberPath="" SelectionChanged="compilationYearCombo_SelectionChanged" IsSynchronizedWithCurrentItem="True" Grid.ColumnSpan="2" IsEditable="False" SelectedIndex="0" IsReadOnly="False" Text="Years">
</RSControls:SmoothScrollComboBox>
I tried adding a <TextBlock Text="Years" /> , but that only changed all the elements in the combo to "Years".
I apreciatte a detail explenation how to this, I am just a beginner with WPF.
Thanks.
You can add a visibility converter to your TextBlock
<TextBlock
Visibility="{Binding SelectedItem, ElementName=compilationYearCombo, Converter={StaticResource NullToVisibilityConverter}}"
IsHitTestVisible="False"
Text="Years" />
with this converter:
public class NullToVisibilityConverter : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
To show the default text ' -- Select Value --' in Combo Box
<ComboBox Height="23" HorizontalAlignment="Left" Margin="180,18,0,0" Name="cmbExportData" VerticalAlignment="Top" Width="148" ItemsSource="{Binding}" Text="-- Select Value --" AllowDrop="False" IsEditable="True" IsManipulationEnabled="False" IsReadOnly="True" />

Categories

Resources