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.
Related
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.
I'm trying to pass my current culture (that has a custom decimal symbol) to WPF, so that it will display bound values according to my region and language settings in windows.
My researches always ended up with the a solution similar to this, which passes the language tag, but not any additional settings (like the decimal symbol).
How can I force WPF to use the whole current culture and not only the default language settings?
Questions about possible a possible workaround:
Can I somehow pass the current culture to the default value converters used by WPF? Or maybe override them?
There's couple options. Maybe the easiest one is to wrap the values you want to databind to screen and call ToString for them. For example, if you have:
public decimal Value
{
get { return this.value; }
set
{
if (value == this.value) return;
this.value = value;
OnPropertyChanged();
}
}
Wrap it inside your ViewModel like this:
public decimal Value
{
get { return this.value; }
set
{
if (value == this.value) return;
this.value = value;
OnPropertyChanged("ValueString");
}
}
public string ValueString
{
get { return this.value.ToString(CultureInfo.CurrentCulture); }
}
And bind your UI against this new property:
<TextBlock x:Name="Result" Text="{Binding ValueString}" Grid.Row="0"/>
This way you will automatically get the formatting based on your computer's culture settings:
Another alternative is to use the method presented in here: https://stackoverflow.com/a/19796279/66988
So you need a custom Binding class:
public class CultureAwareBinding : Binding
{
public CultureAwareBinding(string path)
: base(path)
{
ConverterCulture = CultureInfo.CurrentCulture;
}
}
And then you have to use that in your XAML:
<TextBlock x:Name="Result" Text="{wpfApplication9:CultureAwareBinding Value}" Grid.Row="0"/>
After which you should see the desired output:
using System;
using System.Globalization;
using System.Threading;
using System.Windows;
using System.Windows.Markup;
namespace WPF_CultureExample
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("tr-TR");
var currentCulture = Thread.CurrentThread.CurrentCulture.Name;
var ci = new CultureInfo(currentCulture)
{
NumberFormat = { NumberDecimalSeparator = "," },
DateTimeFormat = { DateSeparator = "." }
};
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
base.OnStartup(e);
}
}
}
You can recode the OnStartup() method in the backend codes of the App.xaml file.
My class has a property that looks like this:
public string DueDateAsString
{
get
{
DateTime duedate = this.RigActionType.FrequencyType.GetDueDateForAction(this);
if (this.HasBeenCompleted(duedate))
{
return "Completed";
}
else if (DateTime.Compare(DateTime.Today, duedate) > 0) // past due
{
return duedate.ToString() + " (past due)";
}
return duedate.ToString();
}
}
I would like to extend the functionality a bit more so that this could also return something like "due in n days" but in a way that I don't have to create a separate property called VerboseDueDateAsString (or something).
Is it possible to do something like this:
someObject.DueDateAsString; // Outputs "4/1/2014"
someObject.DueDateAsString.Verbose; // Outputs "Due in x days"
You could expose the due date as a property and create an extension method for the conversion. Place it in a static class whose namespace is visible where you need it.
public static string Verbose(this DateTime date)
{
return String.Format("Due in {0} days", (DateTime.Now - date).Days);
}
Then apply it directly to the due date
Console.WriteLine(someObject.DueDate.Verbose());
If you replace your actual property with a similar exetension method you will get a consitent way of displaying due dates
public static string Concise(this DateTime date)
{
// Place the logic of DueDateAsString here
}
Console.WriteLine(someObject.DueDate.Concise());
DueDateAsString doesn’t really seem like it should be a property in the first place.
struct DueDate {
DateTime date;
bool completed;
public DueDate(DateTime date, bool completed) {
this.date = date;
this.completed = completed;
}
public override string ToString() {
if (this.completed) {
return "Completed";
}
if (DateTime.Compare(DateTime.Today, duedate) > 0) // past due
{
return duedate.ToString() + " (past due)";
}
return duedate.ToString();
}
public string ToVerboseString() {
// Implement this
}
}
⋮
public DueDate DueDate
{
get
{
DateTime duedate = this.RigActionType.FrequencyType.GetDueDateForAction(this);
return new DueDate(duedate, this.HasBeenCompleted(duedate));
}
}
You could use an extension method on DateTime, but then there’s still the matter of determining whether it’s completed or not.
Name it something other than DueDate, by the way.
DueDateAsString would need to be an object that itself contains a Verbose method afaik
I have a DGV bound to a list of objects whose properties include a DateTime value. I'd like to display, and allow editing the Date and Time components in separate columns. How would I do this?
Here's how I'd do it.
Make your property that exposes the DateTime (together) invisible in the DataGridView.
Have two other properties, Date and Time and have these properties essentially link back to your DateTime property.
Like this:
[Browsable(false)]
public DateTime DateTime { get; set; }
public DateTime Date
{
get { return this.DateTime.Date; }
set
{
TimeSpan time = this.Time;
this.DateTime = value.Date + time;
}
}
public TimeSpan Time
{
get { return this.DateTime.TimeOfDay; }
set
{
this.DateTime = this.Date + value;
}
}
I have a custom control that print the current date into the page.
The control has a Format property for setting witch DateTime property to be printed. (Date, Day, Year etc...)
<TSC:DateTimeWriter runat="server" Format="Year" />
But what i want is when i type :
Format="
I want to show a list of all the possible values(Using Visual Studio).
The cs code:
public class DateTimeWriter : Control
{
public string Format { get; set; }
protected override void Render(HtmlTextWriter writer)
{
writer.Write(writeDateTime());
}
private string writeDateTime()
{
var now = DateTime.Now;
switch (Format)
{
case "Year":
return now.Year.ToString();
case "Day":
return now.Day.ToString();
etc...
default:
return now.ToString();
}
}
}
If you make the Format property an enum instead of a string, VS will be able to display a list of supported formats. E.g.:
public enum DateTimeFormat
{
Year,
...
}
Create an enumerated Type
namespace YourNameSpace
{
[Serializable()]
public enum DateFormat
{
Date,
Day,
Year
}
}
then add a property to your control:
/// <summary>
/// Date Format
/// </summary>
public DateFormat DateFormat
{
get
{
if (ViewState["DateFormat"] == null || ViewState["DateFormat"].ToString().Trim() == String.Empty)
{
return DateFormat.Date; //Default
}
return (DateFormat)ViewState["DateFormat"];
}
set
{
ViewState["DateFormat"] = value;
}
}