How to use CalenderView in UWP MVVM - c#

I want to bind the selected Calender View Item and set it to
a DateTime Variable.
My CalenderView Xaml looks like:
<CalendarView Grid.Row="6" Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20"/>
I have an DateTime item in the Datacontext class:
private DateTime _DueDate;
public DateTime DueDate
{
get { return this._DueDate; }
set
{
if (this._DueDate != value)
{
this._DueDate = value;
base.PropertyOnChanged("DueDate");
}
}
}
And the DateTimeConverter:
public class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
DateTime date = ((DateTime)value);
return date.Day + "." + date.Month + "." + date.Year;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return DateTime.Parse((string)value);
}
}
Here is also the Doc to the Calender View:
CalenderView MSDN
In the Docs is a Property SelectedDate, but I only see in the XAML SelectedDateChanged EventHandler. But I want to do it in MVVM.
My Problem is I don´t know on which Property I can set the
Binding. I looked in the Doc but I only find the Date="" property
from the DatePicker but I don´t find anything to the CalenderView.
UPDATE
Following to the Comment from
#Juo Zuo:"CalendarView has a SelectedDates property. Usually, we can use this property to set the selected date like: MyCalendarView.SelectedDates.Add(new DateTime(2016, 5, 5));. However this property is read-only, we can't use it for binding. So, I'm afraid there is no way to set selected dates with Binding"
I would expand the Question.
My Question is:
Is there any way to use the Calender View with the MVVM Pattern from MSDN ?

All you need to do is to create an attached property and encapsulate the SelectedDates.Add logic within it.
public static class CalendarViewHelper
{
public static IList<DateTimeOffset> GetSelectedDates(DependencyObject obj)
{
return (IList<DateTimeOffset>)obj.GetValue(SelectedDatesProperty);
}
public static void SetSelectedDates(DependencyObject obj, IList<DateTimeOffset> value)
{
obj.SetValue(SelectedDatesProperty, value);
}
public static readonly DependencyProperty SelectedDatesProperty =
DependencyProperty.RegisterAttached("SelectedDates", typeof(IList<DateTimeOffset>), typeof(CalendarView),
new PropertyMetadata(null, (d, e) =>
{
var cv = d as CalendarView;
var dates = e.NewValue as IList<DateTimeOffset>;
if (cv != null && dates != null)
{
foreach (var date in dates)
{
cv.SelectedDates.Add(date);
}
}
}));
}
<CalendarView local:CalendarViewHelper.SelectedDates="{x:Bind Dates, Mode=OneWay}" />
If your Dates property has more than one items inside, make sure you change the SelectionMode to Multiple.

Related

Xamarin Forms - toggle between button states

I have this form in my Xamarin.Forms application where I have two buttons, that are both meant to update a boolean value. Depending on whether that value is true or false, I want only one of the buttons to be enabled. Think of them as a "door": one button sets the "exit" boolean to true and the other to "false". So when the "enter" button is clicked I want it to be disabled until the user "exits" by clicking the "exit" button.
CanExecute/ChangeCanExecute should be the way to go here, at least by my own knowledge - and that's what I've tried.
But it doesn't seem to be working, even when I abstract that functionality on a simpler content page.
I have attached a sample of my ViewModel's code, simplified for clarity.
I can't understand why I'm stumped by something that is so simple outside of MVVM conventions.
public bool _hasWorkerExit;
public bool hasWorkerExit
{
get { return _hasWorkerExit; }
set
{
_hasWorkerExit = value;
OnPropertyChanged();
EnterCommand?.ChangeCanExecute();
ExitCommand?.ChangeCanExecute();
}
}
public Command EnterCommand => new Command(SendWorkerEntry,WorkerCanEnter());
public Command ExitCommand => new Command(SendWorkerExit,WorkerCanExit());
private Func<bool> WorkerCanEnter()
{
return new Func<bool>(() => hasWorkerExit);
}
private Func<bool> WorkerCanExit()
{
return new Func<bool>(() => !hasWorkerExit);
}
private void SendWorkerEntry()
{
// Do the work you're meant to do
hasWorkerExit = false;
}
private void SendWorkerExit()
{
// Do the work you're meant to do
hasWorkerExit = true;
}
Here's the .xaml code for the buttons
<dxe:SimpleButton Grid.Column="0"
FontSize="13"
Text="Enter"
BorderThickness="0"
BackgroundColor="{StaticResource ButtonColour}"
PressedBackgroundColor="{StaticResource PressedButtonColour}"
TextColor="{StaticResource ButtonTextColour}"
PressedTextColor="{StaticResource ButtonTextColour}"
DisabledBackgroundColor="{StaticResource DisabledButtonColour}"
CornerRadius="0"
CornerMode="Round"
Command="{Binding EnterCommand}"></dxe:SimpleButton>
<dxe:SimpleButton Grid.Column="1"
FontSize="13"
Text="Exit"
BorderThickness="0"
BackgroundColor="{StaticResource ButtonColour}"
PressedBackgroundColor="{StaticResource PressedButtonColour}"
TextColor="{StaticResource ButtonTextColour}"
PressedTextColor="{StaticResource ButtonTextColour}"
DisabledBackgroundColor="{StaticResource DisabledButtonColour}"
CornerRadius="0"
CornerMode="Round"
Command="{Binding ExitCommand}"></dxe:SimpleButton>
You can try:
Button 1:
IsEnabled="{Binding HasWorkerExit}"
Button 2:
IsEnabled="{Binding HasWorkerExit, Converter={Helpers:InverseBoolConverter}}"}"
One property alone should solve your problem.
public bool _hasWorkerExit;
public bool HasWorkerExit
{
get { return _hasWorkerExit; }
set
{
_hasWorkerExit = !_hasWorkerExit;
OnPropertyChanged();
}
}
Invert Helper code:
public class InverseBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !((bool)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
//throw new NotImplementedException();
}
}
Try this instead of using the Func<bool>, you can use a simple method group for the Commands which should suffice:
public Command EnterCommand => new Command(SendWorkerEntry, WorkerCanEnter);
public Command ExitCommand => new Command(SendWorkerExit, WorkerCanExit);
private bool WorkerCanEnter() => hasWorkerExit;
private bool WorkerCanExit() => !hasWorkerExit;
Alternatively, this should also work:
public Command EnterCommand => new Command(SendWorkerEntry, () => hasWorkerExit);
public Command ExitCommand => new Command(SendWorkerExit, () => !hasWorkerExit);
Please be aware that CanExecute is not called multiple times, so it is not a dynamic option to use for enabling/disabling the button.(The returning value actually is always false).
Suggestion: You could use a bound value IsEnabled instead of that.
Hope it helps.

Is there any way to execute Textbox UpdateSourceTrigger=LostFocus before Lost Focus Event?

I have a TextBox of which the Text property must be updated before executing the LostFocus event, because in the LostFocus event I use the values of the Text property for calculations.
Currently when entering the LostFocus event (txtTotaisNfe_LostFocus) the ThisDataContext.DescontoTotal has not yet had its value updated.
P.S: I cannot use UpdateSourceTrigger = PropertyChanged because I use a converter (PriceConverter1) in WPF that can only be executed after I have entered the complete value in the TextBox. It converts the entered value into 2 decimal cases value (that is, when running LostFocus).
The question is: Is there any way in the .NET process queue to understand that it must first run the LostFocus from UpdateSourceTrigger and then the LostFocus (txtTotaisNfe_LostFocus)?
WPF Code (DescontoTotal = ThisDataContext.Desconto):
<TextBox Text="{Binding DescontoTotal, Converter={StaticResource PriceConverter1}, Mode=TwoWay, UpdateSourceTrigger=Explicit}" LostFocus="txtTotaisNfe_LostFocus"/>
LostFocus Event Code:
private void txtTotaisNfe_LostFocus(object sender, RoutedEventArgs e)
{
//Rateia o Total de Desconto da NFe entre os Produtos.
foreach (var item in _lsProdutos)
{
item.Desconto = (ThisDataContext.DescontoTotal / ThisDataContext.TotalProdutos * item.ValorProduto).Round();
}
}
PriceConverter1 Code (Please ignore Best Practices in this):
public class PriceConverter1 : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
try
{
return ((decimal)value).ToString("##,###,##0.00");
}
catch
{
return "0.00";
}
}
else
{
return "0.00";
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string price = value.ToString();
decimal result;
if (decimal.TryParse(price, System.Globalization.NumberStyles.Any, null, out result))
{
return result;
}
return value;
}
}

Item to Display for Picker don't show up on load

This is Xamarin Forms app. I'm using Fresh MVVM. I have Modification Page, where i can change boolean value with picker (true, false, null).
I have list of boolean values (for each picker - one value and in ViewModel list filled from DB).Bool converts (using converter) to object with two values: Text(string) and Value(bool?) which is class - CheckListValue written below.
The logic - i'm putting some values with picker, saving it to DB and after i can modify it, so on load, i should see chosen value. But picker field - empty.
Here is result, what i see. I should see Binded Item in ItemDisplayBinding, and its Text (Negative, Positive or Empty).
I thought that the problem in Binding, but it seems okay.
<Picker Grid.Row="1" Grid.Column="0" ItemsSource="{Binding CheckListValueList, Mode=TwoWay}"
ItemDisplayBinding="{Binding Text}" SelectedItem="{Binding CheckListProperties.SomeBooleanValue, Mode=TwoWay, Converter={StaticResource BoolToCheckListConverter}}"/>
here is CheckListValue
public static CheckListValue Positive=> new CheckListValue
{
Text = "Positive",
Value = true
};
public static CheckListValue Negative=> new CheckListValue
{
Text = "Negative",
Value = false
};
public static CheckListValue Empty=> new CheckListValue
{
Text = "Empty",
Value = null
};
public static List<CheckListValue> All => new List<CheckListValue>
{
Positive, Negative, Empty
};
}
public class CheckListValue
{
public string Text { get; set; }
public bool? Value { get; set; }
}
And converter:
public class BoolNullableToCheckListValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var boolValue = value as bool?;
if (!boolValue.HasValue)
return CheckListValues.Empty;
return boolValue.Value ? CheckListValues.Positive : CheckListValues.Negative;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var checkListValue = value as CheckListValue;
return checkListValue?.Value;
}
}
ViewModel:
public List<CheckListValue> CheckListValueList => CheckListValues.All;
public CheckListProperties CheckListProperties { get; set; }
public override void Init(object initData)
{
//Here CheckListProperties takes from DB on every load of Page
}
public class CheckListProperties
{
public bool? PickerBool1 { get; set; }
public bool? PickerBool2 { get; set; }
public bool? PickerBool3 { get; set; }
}
When i'm choosing from picker it works good, changes bool correctly and displays text, but this is modification page and on load, i should see already chosen before values, but its not. Its empty.
Do you know why it could be? Because i have no idea.
Thank you in advance, guys!

Display label text in uppercase using xaml in Xamarin.Forms

I have an username label and need to view this as uppercase but this should only relate to the UI. The data (string) should be saved in the db as actual case whatever it is. Could anyone tell me if there is anyway to convert it to uppercase without doing so through the code behind?
You can use Label.TextTransform with TextTransform.Uppercase.
XAML
<Label TextTransform="Uppercase" />
C#
var label = new Label
{
TextTransform = TextTransform.Uppercase
};
As you're aware you can do this from the code behind as such:
string data = "my data";
UILabel myLabel = new UILabel();
myLabel.Text = data.ToUpper();
So bearing in mind that you don't want to do it this way you would need to derive from UILabel and create your own, then simply add the ToUpper() onto the end of the get;set; values of the Text property.
using CoreGraphics;
using System;
using UIKit;
namespace MyApp.Controls
{
partial class Control_UpperLabel : UILabel
{
public Control_UpperLabel IntPtr handle) : base(handle)
{
//
}
public Control_UpperLabel()
{
//
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
}
public override string Text { get => base.Text.ToUpper(); set => base.Text = value.ToUpper(); }
}
}
EDIT: As per comments below, here is an alternative solution for Xamarin.Forms
This uses a value converter as part of a binding solution. It's also been slightly amended to use the suggestion by clint in the comments below. Thanks.
public class StringCaseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch ((parameter as string).ToUpper()[0])
{
case 'U':
return ((string)value).ToUpper();
case 'L':
return ((string)value).ToLower();
default:
return ((string)value);
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
It would be used in the XAML as such:
Text="{Binding Text, Converter={StaticResource caseConverter}, ConverterParameter=u}}"
Or you can use Bindable property then format the text on the getter :
e.g.:
public static readonly BindableProperty ItemLabelProperty =
BindableProperty.Create(nameof(ItemLabel), typeof(string),
typeof(DetailsLineItemControl), default(string), BindingMode.OneWay);
public string ItemLabel
{
get
{
var value = (string)GetValue(ItemLabelProperty);
return !string.IsNullOrEmpty(value) ? value.ToUpper() : value;
}
set
{
SetValue(ItemLabelProperty, value);
}
}

How to set property in IDataErrorInfo validator from Xaml

When using IDataErrorInfo in WPF is there a way to pass parameters to the validator. For instance I have a DueDate Datepicker. When validating for a new task I want to restrict the date allowed to today or later but when editing I need to allow for DueDates before today since a task can be edited that is past due.
My DatePicker in Xaml (.Net 4.0)
<DatePicker SelectedDate="{Binding Path=SelectedIssue.IssDueDate,
ValidatesOnDataErrors=True}" />
My IErrorDataInfo
namespace OITaskManager.Model
{
public partial class Issue : IDataErrorInfo
{
// I want to set these values from the Xaml
public DateTime minDate = new DateTime(2009, 1, 1);
public DateTime maxDate = new DateTime(2025, 12, 31);
public string this[string columnName]
{
get
{
if (columnName == "IssDueDate")
{
if (IssDueDate < minDate || IssDueDate > maxDate)
{
return "Due Date must be later than " + minDate.Date +
" and earlier than " + maxDate.Date;
}
return null;
}
return null;
}
}
You could just use a custom validator on the binding. Or you could maintain a IsNew internal state on the the Issue object instance until it is no longer considered new.

Categories