Windows Store App Collapse TextBlock if value is null using Style.xaml - xaml

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}}"/>

Related

Binding property to control

How do I bind SourceObject and TargetObject to the TextBox-Element?
This works, but I want more than one textbox and that does not seem to be possible when they are named the same.
My goal is to have the TextBox change its background color when focused.
<TextBox xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
xmlns:ia="clr-namespace:Avalonia.Xaml.Interactions.Core;assembly=Avalonia.Xaml.Interactions"
x:Class="Test.View.CustomTextBox"
Name="textBox">
<i:Interaction.Behaviors>
<ia:EventTriggerBehavior EventName="GotFocus" SourceObject="{Binding #textBox}">
<ia:ChangePropertyAction TargetObject="{Binding #textBox}" PropertyName="Background" Value="{StaticResource FocusedBackgroundColor}"/>
</ia:EventTriggerBehavior>
</i:Interaction.Behaviors>
</TextBox>
Thanks a lot!
You can use RelativeSource and converter, something like that:
public class BoolColorBrushConverter : IValueConverter
{
public Brush TrueBrush {get;set;}
public Brush FalseBrush {get;set;}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is bool b && b)
return TrueBrush;
else
return FalseBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotSupportedException();
}
xaml:
<MyControl>
<MyControl.Resources>
<BoolBrushConverter TrueColor="Red" FalseColor="Blue" x:Key="TextBoxFocusedBackgroundConverter"/>
</MyControl.Resources>
<TextBox Background="{Binding IsFocused, RelativeSource={RelativeSource Self}, Converter={StaticResource TextBoxFocusedBackgroundConverter}}}"/>;
</MyControl>

How to add : with label where text value is binding dynamically?

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>

AutomationProperties.HelpText doesn't work on UWP ListView

I have a ListView like this:
<ListView x:Name="ArtistsList"
ItemsSource="{Binding Source={StaticResource ArtistsCVS}}"
SelectionMode="None"
ItemContainerStyle="{StaticResource ListViewContainerStrecher}"
IsItemClickEnabled="True"
ItemClick="ArtistsList_ItemClick">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:DAPP">
<Grid AutomationProperties.Name="{Binding artist}"
AutomationProperties.HelpText="Navigate to artist info page.">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
MaxWidth="60"
Source="{Binding thumb}"
HorizontalAlignment="Center"/>
<Grid Grid.Column="1" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding artist}"/>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When I try to use Narrator it reads the Artist name but it doesn't read help text. Also, I want to know if is it possible to bind two values a AutomationProperties.Name?
For example, I have an ArtistName and a SongName then for example use AutomationProperties.Name = "{Binding ArtistName};{Binding songName}" then it reads something like Artist (little pause) SongName.
When I try to use Narrator it reads the Artist name but it doesn't read help text.
Setting AutomationProperties.HelpText attached property inside DataTemplate won't work here. To solve this issue, we can using a custom ListView and overriding PrepareContainerForItemOverride method to set automation properties. And this is also the recommended way for adding accessibility support to the items in a ListView.
For example:
public class MyList : ListView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
FrameworkElement source = element as FrameworkElement;
source.SetBinding(AutomationProperties.NameProperty, new Binding
{
Path = new PropertyPath("Content.artist"),
RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.Self }
});
AutomationProperties.SetHelpText(source, "Navigate to artist info page.");
}
}
Then you can use MyList instead of ListView and there is no need to set AutomationProperties.Name and AutomationProperties.HelpText in Grid any more. For more info, please see XAML accessibility sample.
I want to know is it possible to bind two values a AutomationProperties.Name?
UWP has no multibinding support out of the box. But if the ArtistName and songName come form one model or view model, then we can use a Converter to achieve this like:
public class AutomationPropertiesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
//Suppose ArtistName and songName are the properties of Song class
var song = (Song)value;
return $"{song?.ArtistName} - {song?.songName}";
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
And use the Converter like:
public class MyList : ListView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
FrameworkElement source = element as FrameworkElement;
//Suppose Song class is the DataType of the DataTemplate
source.SetBinding(AutomationProperties.NameProperty, new Binding
{
Path = new PropertyPath("Content"),
RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.Self },
Converter = new AutomationPropertiesConverter()
});
AutomationProperties.SetHelpText(source, "Navigate to artist info page.");
}
}

Universal Windows Apps 8.1 DatePicker and TimePicker setting default string

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).

slider control and textblock control interaction-Metro apps

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!