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).
Related
I am creating an application using the Master details page. In that, there is one thing that I missed out is that when I open an application than at that time the first item is not selected here.
I try with different solutions like make "Custom View Cell" and make a renderer for solving that but there is also the same issue is raised.
I also mention the image below.
Is there any solution in regards to that?
It's a bit complicated , you can do it totally in Forms project without custom renderer.
I list the steps to achieve what you want .
Give the Model property to indicate which one is selected and implement `INotifyPropertyChanged.
public class MasterPageItem : INotifyPropertyChanged
{
private bool isSelected;
public bool IsSelected {
get {
return isSelected;
}
set {
if (value != this.isSelected)
{
this.isSelected = value;
NotifyPropertyChanged();
}
}
}
}
Bind with the background color of parent view in ViewCell and convert bool value to color in Converter
<ViewCell>
<Grid Padding="5,10" BackgroundColor="{Binding IsSelected , Converter={StaticResource BooltoColor}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource}" />
<Label Grid.Column="1" Text="{Binding Title}" />
</Grid>
</ViewCell>
public class BooltoColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color color ;
if(((bool)value) == true)
{
color = Color.Gray;
}
else
{
color = Color.Transparent;
}
return color;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return true;
}
}
Set the item as selected and set other item disselected when you tap the listview item.
private void ListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
foreach (MasterPageItem i in list)
{
i.IsSelected = false;
}
MasterPageItem item = e.Item as MasterPageItem;
if (item != null)
{
item.IsSelected = true;
list.RemoveAt(e.ItemIndex);
list.Insert(e.ItemIndex, item);
}
}
Check my testing image and sample link below
https://github.com/ColeXm/MasterDetailedSample/blob/master/Xamarin_Forms___MasterDetailPage.zip
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>
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.");
}
}
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!
Need some help in ListBox DataBindg in Silverlight for Windows Phone. The code as follows:
1) On Page Load Event :
Note : Pictures is a collection of picture, PicNames is collection of names of pictures.
var ml = new MediaLibrary();
var ChkPics = ml.Pictures;
var PicNames = from p in ChkPics
where p.Name.Contains("s")
select p;
2) Static Class
public static class PhotoNames
{
private static List<string> m_Photoname = new List<string>();
public static List<string> PhotoFileNames
{
get
{
return m_Photoname;
}
set
{
m_Photoname = value;
}
}
}
After getting all the photo filenames in the PicNames in this way:
On Page Load Event :
var ml = new MediaLibrary();
var ChkPics = ml.Pictures;
var PicNames = from p in ChkPics
where p.Name.Contains("s")
select p;
foreach (var pic in PicNames)
{
PhotoNames.PhotoFileNames.Add(pic.Name);
}
How do I bind a ListBox to this static class and show all the data in TextBlock inside ListBox?
Thanks.
It looks like ml.Pictures has all the info you need (name and picture). Why do you need the static class?
You could do the following:
var ml = new MediaLibrary();
listBox.ItemSource = ml.Pictures.Where(picture => picture.Name.Contains("s"));
And in your XAML:
<UserControl.Resources>
<local:ImageConverter x:Key="ImageConverter"></local:ImageConverter>
...
</UserControl.Resources>
<ListBox x:Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="35"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding Name}"></TextBlock>
<Image Grid.Column="1" Grid.Row="0" Source="{Binding Picture, Converter={StaticResource ImageConverter}}"></Image>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The template shows both the picture's name and the picture itself in a thumbnail, if you don't need the picture, use DisplayMemberPath instead.
<ListBox x:Name="listBox" DisplayMemberpath="Name">
</ListBox>
/// <summary>
/// Converts an image path to the associated image.
/// </summary>
public class ImageConverter : IValueConverter
{
#region IValueConverter implementation
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string imagePath = (string)value;
Uri Uri = new Uri(imagePath, UriKind.Relative);
return new BitmapImage(Uri);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}