Remove Blackout Dates from WPF Calendar Blackout Date Collection - c#

So I wanted to Blackout all dates from 2000 from present in the WPF Calendar that aren't in a Datetime list.
My thought was to blackout all dates individually from 2000 to now and then remove each date from the blackout Date Collection.
This Code adds dates fine but it doesn't work to remove the dates from the collection.
var DateList = FI.Select(x => x.LastWriteTime.Date).Distinct().ToList();
for (var day = new DateTime(2000,1,1); day.Date <= DateTime.Now.Date; day = day.AddDays(1))
{
Calendar.BlackoutDates.Add(new CalendarDateRange(day));
}
foreach (DateTime k in Datelist)
{
Calendar.BlackoutDates.Remove(new CalendarDateRange(k));
}
I compared the date range from the blackout date collection and the newly created one from the current iteration of the list but it says they aren't equivalent.
Comparison seen here
Thank you for the assistance.

CalendarDateRange class lets you specify a start date and end date for the range, you don't have to add a CalendarDateRange for every day.
https://msdn.microsoft.com/en-us/library/system.windows.controls.calendardaterange(v=vs.110).aspx
Also, there are a lot of code examples on the Calendar.BlackoutDates documentation :
https://msdn.microsoft.com/en-us/library/system.windows.controls.calendar.blackoutdates(v=vs.110).aspx
var DateList = FI.Select(x => x.LastWriteTime.Date).Distinct().ToList();
//Add all dates between DateTime.MinValue and the day before your DateList min value.
Calendar.BlackoutDates.Add(new CalendarDateRange(DateTime.MinValue, DateList.Min().AddDays(-1)));
** EDIT **
After reading your comment, it seems that I've misunderstood your issue. You're trying to remove a new instance of CalendarDateRange, which is different than the CalendarDateRange instance that was added to the collection, even though they have the same start and end values.
Replace your foreach block with this one to fix your issue :
foreach (var k in DateList)
{
while (Calendar.BlackoutDates.Any(bd => bd.Start.Date == k.Date))
{
Calendar.BlackoutDates.Remove(Calendar.BlackoutDates.FirstOrDefault(bd => bd.Start.Date == k.Date));
}
}

Related

Find a date from a specific list of date

I am a beginner in c # and I can not find the solution for my problem.
I am creating a personal project that allows me to send reminders, I have a date list and I need to do tasks between two specific dates in real life.
I found how to get the next date from today's date but I can't find how to get the previous one
Here is my sample code
void calc_x_date()
{
List<string> x_dates = new List<string>();
x_dates.Add("10/01/2017");
x_dates.Add("14/02/2017");
x_dates.Add("14/03/2017");
x_dates.Add("11/04/2017");
x_dates.Add("09/05/2017");
x_dates.Add("13/06/2017");
x_dates.Add("04/07/2017");
x_dates.Add("08/08/2017");
x_dates.Add("12/09/2017");
x_dates.Add("10/10/2017");
x_dates.Add("14/11/2017");
x_dates.Add("12/12/2017");
var allDates = x_dates.Select(DateTime.Parse).OrderBy(d => d).ToList();
var todayDate = DateTime.Today;
var nextDate = todayDate >= allDates.Last()
? allDates.Last()
: todayDate <= allDates.First()
? allDates.First()
: allDates.First(d => d >= todayDate);
string NextDate = nextDate.ToString(); // the closest next date from today
//string PreviousDate = // the closest previous date from today
}
Could someone explain me how to find my previous date please ?
Thanks in advance
I'd suggest using List<T>.BinarySearch: that will find the index of the date. If the index is 0 or more, then the exact date was found. If it's negative, then taking ~index will get you the index where the date would have been inserted.
Once you've got that information, it's easy to find the value at the previous index or the next index - but you should consider all the cases of:
Today is before all dates
Today is after all dates
Today is a date between the first and last date in the list, but isn't in the list
Today is equal to the first date
Today is equal to the last date
Today is equal to a date in the list which isn't the first or last date
As asides:
I would strongly encourage you to get in the habit of following .NET naming conventions as early as possible
I'd encourage you not to use strings to represent dates unless you really need to
If you're doing a lot of date/time work, you may find my Noda Time library easier to use correctly than DateTime
Here is a Linq approach
List<string> x_dates = new List<string>();
x_dates.Add("10/01/2017");
x_dates.Add("14/02/2017");
x_dates.Add("14/03/2017");
x_dates.Add("11/04/2017");
x_dates.Add("09/05/2017");
x_dates.Add("13/06/2017");
x_dates.Add("04/07/2017");
x_dates.Add("08/08/2017");
x_dates.Add("12/09/2017");
x_dates.Add("10/10/2017");
x_dates.Add("14/11/2017");
x_dates.Add("12/12/2017");
DateTime today = DateTime.Today;
IEnumerable<DateTime> dt_dates = x_dates.Select(DateTime.Parse);
DateTime prev = dt_dates.Where(x => x < today)
.OrderByDescending(x => x)
.First();
DateTime next = dt_dates.Where(x => x > today)
.OrderBy(x => x)
.First();
alternative solution
DateTime prev = dt_dates.Where(x => x < today).Max();
DateTime next = dt_dates.Where(x => x > today).Min();
Storing dates in string format works. It is however incredibly difficult to do date comparisons. You have to first cast it to numbers, handle the exceptions, etc.
C# has a DateTime object. You can store dates in this and ignore the time. DateTime objects can be compared using the < and > operators.
If you create a class with a start date and an end date, store these objects in a list(of tasks), would that solve your problem? You can also add a text of the task in a string to said object.

How do I populate a dropdown list with the past 30 days of dates

I am trying to populate a Dropdown list with the past 30 dates and I am receiving the error:
An exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll but was not handled in user code
This is my function to fill the Drop Down List:
public void FillDates(int NumDaysBack)
{
for (DateTime d = DateTime.Now.AddDays(-NumDaysBack); d < DateTime.Now; d.AddDays(1))
{
ddMiscDateList.Items.Add(d.ToShortDateString());
}
ddMiscDateList.Items.Add("Other");
}
I am calling this function on load and using 30 for NumDaysBack. How can I write this more efficiently to not receive this error?
DateTime.AddDays() returns new instance of DateTime. It doesn't change d variable. Because of it you have infinite loop.
You can fix it
public void FillDates(int NumDaysBack)
{
for (DateTime d = DateTime.Now.AddDays(-NumDaysBack); d < DateTime.Now; d = d.AddDays(1))
{
ddMiscDateList.Items.Add(d.ToShortDateString());
}
ddMiscDateList.Items.Add("Other");
}
public void FillDates(int NumDaysBack)
{
for (DateTime d = DateTime.Now.AddDays(-NumDaysBack); d < DateTime.Now; d = d.AddDays(1))
//----------------------------------------------------------------------^^^^-fixed here
{
ddMiscDateList.Items.Add(d.ToShortDateString());
}
ddMiscDateList.Items.Add("Other");
}
When you call d.AddDays(1) it returns new instance of DateTime (without updating d)
Invoking d.AddDays(1) you are getting a new instance of DateTime i.e. you are not applying any changes to your DateTime d object. Therefore your loop never terminates and you end up running out of memory.
The solution is to write d = d.AddDays(1) instead.
From the MSDN documentation:
Returns a new DateTime that adds the specified number of days to the value of this instance.
Also, if you're only interested in arithmetic (in your case addition) on actual days, then you may want to omit the actual time part and instead use:
DateTime.Now.Date
or simplified:
DateTime.Today
You will still have the time part but it will be set to 00:00:00
DateTime Today Property:
An object that is set to today's date, with the time component set to 00:00:00.
Because it returns the current date without the current time, the Today property is suitable for use in applications that work with dates only.
Conversely if you only want to use the time of the day use DateTime.TimeOfDay which returns a DateTime object without the current day.
When generating sequences sometimes Enumerable.Range can be a good alternative.
Something like.
public void FillDates(int NumDaysBack)
{
ddMiscDateList.Items = Enumerable.Range(0, NumDaysBack).Select(x => DateTime.Now.AddDays(-NumDaysBack + x));
}

Get days of week by current week

After searching through stack overflow, I cant seem to find a solution. I've put together a chart (Chart.js) and I need to grab days of the current week bind that to the chart and match any days date to one stored in my db thus brining back all data based on that date.
So if anyone could give me any pointers on fetching List from the current week, that would be awesome.
I hope this is clear enough please feel free to ask more questions. Sorry no code struggling to get started. For me DateTime is an absolute nightmare to work with.
Regards,
You can use the DayOfWeek property of DateTime:
new DateTime(2014,11,16).DayOfWeek
So... to deal with a list of dates, first, let's make a list of dates:
var startDate = DateTime.Today;
var endDate = startDate.AddDays(7);
//the number of days in our range of dates
var numDays = (int)((endDate - startDate).TotalDays);
List<DateTime> myDates = Enumerable
//creates an IEnumerable of ints from 0 to numDays
.Range(0, numDays)
//now for each of those numbers (0..numDays),
//select startDate plus x number of days
.Select(x => startDate.AddDays(x))
//and make a list
.ToList();
and get the days of the week:
List<string> myDaysOfWeek = myDates.Select(d => d.DayOfWeek.ToString()).ToList();
if you want the week to start on (say) the previous Monday, you could alter startDate as follows:
startDate = startDate
.AddDays(-(((startDate.DayOfWeek - DayOfWeek.Monday) + 7) % 7));
This works because we can treat the enumeration values of enum DayOfWeek as numbers, so we can subtract Monday(value 1) from Sunday(value 0), which gives -1... then we do a bit of a jiggle to wrap this value to 6 using modulo maths. If you subtract the resulting value (measured in days) from the start date, you end up on the previous Monday.
If you want to know the days of the current week, you need to:
Get the current day
Convert it to an integer
Subtract that many days from the current date. That gives you the date for Sunday.
Create a list, starting with Sunday.
So:
var now = DateTime.Now;
var currentDay = now.DayOfWeek;
int days = (int)currentDay;
DateTime sunday = now.AddDays(-days);
var daysThisWeek = Enumerable.Range(0, 7)
.Select(d => sunday.AddDays(d))
.ToList();

Storing dates in a list using c#

I have two textboxes and a button, both textbox have calender attach to them. I want to store the dates which are between the first textbox and second textbox in a list, I am invoking following method on button click.
private void CollectDates()
{
DateTime StartDate = Convert.ToDateTime(txtFromDate.Text);
DateTime EndDate = Convert.ToDateTime(txtTillDate.Text);
List<DateTime> datelist = new List<DateTime>();
for (StartDate = Convert.ToDateTime(txtFromDate.Text); StartDate < Convert.ToDateTime(txtTillDate.Text); StartDate.AddDays(1))
{
datelist.Add(StartDate);
}
}
But I am getting error after storing the first date in the list: Exception of type 'System.OutOfMemoryException' was thrown.
I think my loop is running endlessly, any help will be appreciated.
DateTime.AddDays() does not change the datetime you must assign its return value. Like
StartDate = StartDate.AddDays(1)
It is indeed an infinite loop. You're stating that if the start date is less than the end date, add start date to the list. It'll keep doing this for infinity as start date should always (in theory) be less than the end date. The add days function isn't assigned to a variable so it never gets added to the start date.
Also another piece of advice with .Net datetime is to use the in-built compare function.
DateTime Compare function
Hope that helps!
Try this:
private void CollectDates()
{
DateTime StartDate = Convert.ToDateTime(txtFromDate.Text);
DateTime EndDate = Convert.ToDateTime(txtTillDate.Text);
List<DateTime> dateList = new List<DateTime>();
DateTime currentDate = StartDate;
while(currentDate <= EndDate)
{
dateList.Add(currentDate);
currentDate.AddDays(1);
}
}
use this
for (int i =0; i<(EndDate-StartDate).Days; i++)
{
datelist.Add(StartDate.AddDays(i));
}
you might want to try linq:
Enumerable.Range(0, (int)endDate.Subtract(startDate).TotalDays)
.Select(d => startDate.AddDays(d))
.ToList()

Populating month and day

I'm populating a combobox with month name as follows:`
var engCulture = new CultureInfo("en-US");
cmbAmCul.Items.AddRange(engCulture.DateTimeFormat.MonthNames);
what is the right way to:
eliminate the blank entry after the
12 month names.
populate another
combobox with day (1-31 || 1-28 ||
1-30) according to the month
selected?
For the first part, you could use a linq query...
var engCulture = new CultureInfo("en-US");
cmbAmCul.Items.AddRange(from m in engCulture.DateTimeFormat.MonthNames
where !String.IsNullOrEmpty(m)
select m);
The DateTimeInfo class supports calendars with 13 months, which is why this occurs.
For the second part, I would go for something like...
for (int i = 1; i <= DateTime.DaysInMonth(year, month); i++) {
cmbDay.Items.Add(i.ToString());
}
Obviously populating the year/month vars from your selected values.
Use String.Trim() to remove blanks from beginning & end of strings
Use return value from DateTime.DaysInMonth(int year, int month) to populate your day combo box
You could also use a DateTime picker from the standard controls or is it not an option for you?
You don't specify what you are trying to build (ASP.NET or Winforms etc) but you could possibly use a Calendar control instead of dropdowns to improve the User experience. Less clicks and less code tho go wrong perhaps.

Categories