i am trying to set the slider control to value from text block's text property through {Binding} on XAML.
<Slider ValueChanged="slider_ValueChanged_1" Value= "{Binding ElementName=ComponentTextBlockValue,Path=Text}" StepFrequency="25"/>
Do i need an converter to set the slider's value . The binding seems to work sometimes but sometimes it doesn't work. Sometimes,the slider just doesn't set its value to text block value.
Since you bind the Slider's value directly without a value converter, I suspect that the binding is broken when the text is not a number or out of range.
You can prevent that by creating a value converter that will prevent bad value to be bound, so the binding will always work.
Here is some example:
public class TextToSliderValueConverter : IValueConverter
{
public double MaximumSliderValue { get; set; }
public double MinimumSliderValue { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
double sliderValue;
if (double.TryParse(value as string, out sliderValue)
&& sliderValue <= MaximumSliderValue && sliderValue >= MinimumSliderValue)
{
return sliderValue;
}
else
{
return 0.0;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Here is the XAML:
<Page
x:Class="stovfSliderTextBox.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:stovfSliderTextBox"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<local:TextToSliderValueConverter x:Key="txtToSliderValue" MaximumSliderValue="100" MinimumSliderValue="0"/>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Slider Value= "{Binding ElementName=ComponentTextBlockValue,Path=Text, Converter={StaticResource txtToSliderValue}, ConverterParameter=slider}" StepFrequency="25"/>
<TextBox x:Name="ComponentTextBlockValue" Width="50"/>
</StackPanel>
</Grid>
</Page>
The TextToSliderValueConverter makes sure that the slider will always get the valid value. If you do not use default Slider.Maximum or Slider.Minimum, you can modify the values accordingly.
Hope this helps!
Related
I am developing a Xamarin app which I am testing on an Android device. I have a XAML view and I am binding an enum property in the viewmodel to multiple controls - one for text value, and the other to background color with an IValueConverter. Relevant XAML code:
<ContentView
BackgroundColor="{Binding MyField, Converter={StaticResource MyFieldEnumValueToColorConverter}}"
>
<ContentView.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding MyFieldClickCommand}" />
</ContentView.GestureRecognizers>
<Label
Text="{Binding MyField}"
/>
</ContentView>
IValueConverter implementation:
public class MyFieldEnumValueToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is MyFieldEnum)
{
switch ((MyFieldEnum)value)
{
case MyFieldEnum.Value1:
return Color.Orange;
case MyFieldEnum.Value2:
return Color.Green;
case MyFieldEnum.Value3:
return Color.Red;
}
}
return Color.White;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Property in the viewmodel (yes, it does implement INotifyPropertyChanged):
public event PropertyChangedEventHandler PropertyChanged;
private MyFieldEnum _myField;
public MyFieldEnum MyField
{
get => _myField;
set
{
_myField= value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyField)));
}
}
When I load this page, the controls load properly for every distinct enum value: the text and the background color both reflect the actual value.
In a click handler, I simply set the property value like this:
MyField = MyFieldEnum.Value2;
The text changes, but the background color does not. Why?
I also tried introducing a new field (of type Color), implement the IValueConverter logic directly in the getter, and bind that to the BackgroundColor attribute of the ContentView. Same issue. The page has many other data-bound items and all work properly except this one.
UPDATE: it appears that the problem is with the ContentView. I put the exact same BackgroundColor binding to the Label itself and there it works as expected, but for the ContentView it does not.
I am using XAML to define a ListView, with multiple buttons for each cell.
I want to trigger visibility depending on whether a string value is empty or not.
My button inside the ListView is:
<Button Text="{Binding Phone}"
Clicked="OnPhoneClicked"
CommandParameter="{Binding Telefono}"
x:Name="btnPhone" />
Binding Phone is read from my model. It is correctly shown.
How can set a IsVisible property button if Phone's value is an empty string?
Try this code
<Button Text="{Binding Phone}"
Clicked="OnPhoneClicked"
CommandParameter="{Binding Telefono}"
x:Name="btnPhone"
IsVisible="{Binding Phone,Converter={StaticResource StringNullOrEmptyBoolConverter"} />
StringNullOrEmptyBoolConverter.cs file
public class StringNullOrEmptyBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var s = value as string;
return !string.IsNullOrWhiteSpace(s);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Finally add this in App.xaml file
<Application.Resources>
<ResourceDictionary>
<Converter:StringNullOrEmptyBoolConverter x:Key="StringNullOrEmptyBoolConverter" />
</ResourceDictionary>
</Application.Resources>
How I can add : with string at my label in xaml in xamarin.forms. I have a text coming from app resource file by (i18n:Translate Text=Supplier). Now with this text I also add : after this text. I don't want to add : in app resource with text. I want to do that it on xaml only. I tried with StringFormat but don't know how I can do it.
You can use a Value Converter to change the value on your Binding, but it's tricky because you can't easily add a converter while using i18n:Translate. But I still see three possible solutions to your problem:
1. Property without Value Converter
The easiest way would be to create a Property which gets the translated text and then adds a colon to your text:
ViewModel:
public string Supplier
{
get { return AppResources.Supplier + ":"; }
}
XAML:
<Label Text="{Binding Supplier}"/>
2. Property with Value converter
Another way is to create a property which gets the translated text and then add the colon via a Value Converter:
ViewModel:
public string Supplier
{
get { return AppResources.Supplier; }
}
Converter class:
public class ColonConverter : 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)
{
return value.ToString().Remove(value.ToString().Length - 1);
}
}
XAML:
<ContentPage.Resources>
<ResourceDictionary>
<local:ColonConverter x:Key="ColonConverter" />
</ResourceDictionary>
</ContentPage.Resources>
...
<Label Text={Binding Supplier, Converter={StaticResource ColonConverter}}"/>
3. Create your own Translate Extension and Value Converter
I didn't test this, but I found this SO answer which gives an example on how to achieve that. This way you don't need to add properties to your ViewModel, so you only have to adjust your XAML once you set up the Translate Extension and Converter. But it's needs some work to write your own Translate Extension.
Custom TranslateExtension:
[ContentProperty("Text")]
public class TranslateExtension : IMarkupExtension
{
const string ResourceId = "Project.Resources.AppResources";
public string Text { get; set; }
public IValueConverter Converter { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Text == null)
return null;
ResourceManager resourceManager = new ResourceManager(ResourceId, typeof(TranslateExtension).GetTypeInfo().Assembly);
string translatedText = resourceManager.GetString(Text, CultureInfo.CurrentCulture);
if (this.Converter != null)
{
translatedText = Converter.Convert(translatedText, typeof(string), null, CultureInfo.CurrentCulture).ToString() ?? translatedText;
}
return translatedText;
}
}
XAML:
xmlns:strings="clr-namespace:Project.Utils;assembly=Project"
<ContentPage.Resources>
<ResourceDictionary>
<converters:ColonSpaceConverter x:Key="ColonSpaceConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<Label Text="{strings:Translate Money, Converter={StaticResource ColonSpaceConverter}}" />
This can be achieved in many ways, drafting two of them: (Value of Label will be changed on sliding the Slider)
Method 1
<Label Text="Slide to change Value"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
x:Name="lblSliderValue" FontSize="Title" Margin="60"></Label>
<Slider ValueChanged="Slider_ValueChanged"></Slider>
And in CodeBehind file,
private void Slider_ValueChanged(object sender, ValueChangedEventArgs e)
{
lblSliderValue.Text = e.NewValue.ToString("0.00");
lblSliderValue.BackgroundColor = Color.Black;
lblSliderValue.TextColor = Color.White;
}
Method 2 (No need of code in CodeBehind file)
<Label Text="Slide to change Value"
VerticalOptions="Center"
HorizontalOptions="Center"
Text="{Binding Source={x:Reference sldExample}, Path=Value, StringFormat='{0:F2}'}"></Label>
<Slider x:Name="sldExample" BackgroundColor="Yellow" ThumbColor="Violet"></Slider>
DatePicker and TimePicker in UWA 8.1 for Windows Store and Windows Phone (WinRT) by default it shows today date and the current time, whereas I want to set initially both the controls to some default string let's say "Set Due Date/Time" because they're optional.
I am binding them to the following properties using MVVM pattern and MVVM light libraries only
public DateTimeOffset? DueDate { get; set; }
public TimeSpan? DueTime { get; set; }
I've tried in the following way, please suggest any solution.
I have used two converters but there is a problem.
When I click the button that says "Set Due Date" and then click the tick mark in the DatePicker popup screen without changing date, month or year then the converter doesn't fire, when I make a change to date, month or year then it fires, I see that even if the property bound is a nullable DateTimeOffset the DatePicker in XAML shows Date value to current date, also IsHitTestVisible="False" removes the tilt effect which is nice to have, because the button can't be clicked anymore, but the tilt effect is not a must have option for me
<Page
x:Class="UWP.MVVM.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWP.MVVM"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:UWP.MVVM.ViewModels"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:converters="using:UWP.MVVM.Converters"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<converters:DateTimeOffsetToVisibilityConverter x:Key="DateTimeOffsetToVisibilityConverter"/>
<converters:DateTimeOffsetToOpacityConverter x:Key="DateTimeOffsetToOpacityConverter"/>
</Page.Resources>
<Grid Margin="24,24">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Header="First Name"
Text="{Binding Person.FirstName}"/>
<DatePicker Name="DateOfBirth"
Date="{Binding Person.DateOfBirth, Mode=TwoWay}"
Grid.Row="1"
Opacity="{Binding Person.DateOfBirth, Converter={StaticResource DateTimeOffsetToOpacityConverter}}"/>
<Button Grid.Row="1"
Content="Set Due Date"
IsHitTestVisible="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Left"
Visibility="{Binding Person.DateOfBirth, Converter={StaticResource DateTimeOffsetToVisibilityConverter}}"/>
</Grid>
</Page>
namespace UWP.MVVM.Converters
{
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
public class DateTimeOffsetToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value == Visibility.Visible)
{
return null;
}
else
{
return DateTimeOffset.Now;
}
}
}
}
namespace UWP.MVVM.Converters
{
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
public class DateTimeOffsetToOpacityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
{
return 0D;
}
else
{
return 1D;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value == 0D)
{
return null;
}
else
{
return DateTimeOffset.Now;
}
}
}
}
You can put a textblock on the datepicker, with your desired text.
Set the visibility of textblock depending upon the value of your DueDate/DueTime properties,using a converter(if its null return visible else return collapsed).
If style definition is:
<Style x:Key="BodyTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BaselineTextStyle}">
<Setter Property="FontWeight" Value="SemiLight"/>
</Style>
How do I add property that would collapse the TextBlock if the value is null?
Thanks.
<TextBlock Visibility="{Binding RelativeSource={RelativeSource Self}, Path=Text,
Converter={StaticResource TextIsNullOrEmptyToVisibilityConverter}}"/>
Then, create a IValueConverter named TextIsNullOrEmptyToVisibilityConverter which takes in a string and returns a Visibility enum based on string.IsNullOrEmpty.
Thanks to Nate for his input. The final solution is shown below.
First create the converter.
public class TextIsNullOrEmptyToVisibilityConverter : IValueConverter
{
public object IValueConverter.Convert(object value, System.Type targetType, object parameter, string language)
{
string Str = (string)value;
if (string.IsNullOrEmpty(Str)) {
return Visibility.Collapsed;
} else {
return Visibility.Visible;
}
}
public object IValueConverter.ConvertBack(object value, System.Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Give the converter a resource key in the page XAML file.
<Page.Resources>
<local:TextIsNullOrEmptyToVisibilityConverter x:Key="visiblityConverter"/>
</Page.Resources>
Apply the resource to the Visibility Attribute as by Nate above.
<TextBlock Visibility="{Binding RelativeSource={RelativeSource Self}, Path=Text,
Converter={StaticResource TextIsNullOrEmptyToVisibilityConverter}}"/>