now i make multiple select calendar, use blazor.
i want get callback after change date.
this is my calendar component source.
<div class="table-responsive-sm">
<table class="table table-sm text-center calendar">
<thead>
<tr>
<th colspan="7">
<button @onclick="(e=> ChangeMonth(-1))" class="btn btn-link">
<
</button>
@($"{CurrentMonth:yyyy.MM}")
<button @onclick="(e=> ChangeMonth(1))" class="btn btn-link">
>
</button>
</th>
</tr>
<tr>
<th scope="col">SUN</th>
<th scope="col">MON</th>
<th scope="col">TUS</th>
<th scope="col">WED</th>
<th scope="col">THU</th>
<th scope="col">FRI</th>
<th scope="col">SAT</th>
</tr>
</thead>
<tbody>
@{
var i = 0;
var prevLastDay = CurrentMonth.AddDays(-1).Day;
}
@for (var row = 0; row < 5; row++)
{
<tr>
@for (var col = 0; col < 7; col++)
{
if (i < (int)StartDayOfWeek)
{
<td style="color:gray;">
@(prevLastDay - ((int)StartDayOfWeek - i))
</td>
}
else if (i >= (DaysInMonth + (int)StartDayOfWeek))
{
<td style="color:gray;">@(i - (DaysInMonth + (int)StartDayOfWeek) + 1)</td>
}
else
{
var day = i - (int)StartDayOfWeek + 1;
<td>
<button class="btn btn-sm btn-block @(DayClass(day))" @onclick="(e=> ToggleDate(day))">
@(day)
</button>
</td>
}
i++;
}
</tr>
}
</tbody>
</table>
</div>
@code {
/// <summary>
/// Current Month
/// </summary>
[Parameter]
public DateTime CurrentMonth { get; set; } = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
/// <summary>
/// Start Day Of First Day In Current Month
///</summary>
private DayOfWeek StartDayOfWeek => CurrentMonth.DayOfWeek;
/// <summary>
/// Selected Day List
/// </summary>
[Parameter]
public List<DateTime> SelectedDays { get; set; } = new List<DateTime>();
[Parameter]
public EventCallback<List<DateTime>> SelectedDaysChanged { get; set; }
/// <summary>
/// Selectable Day List
/// </summary>
[Parameter]
public List<DateTime> SelectableDays { get; set; } = new List<DateTime>();
[Parameter]
public EventCallback<DateTime> CurrentMonthChanged { get; set; }
private int DaysInMonth => DateTime.DaysInMonth(CurrentMonth.Year, CurrentMonth.Month);
protected override void OnParametersSet()
{
base.OnParametersSet();
CurrentMonth = CurrentMonth.AddDays(CurrentMonth.Day * -1 + 1);
}
protected override void OnInitialized()
{
}
public bool IsSelectable(DateTime date)
{
return SelectableDays.Select(p => p.Date).Contains(date.Date);
}
public string DayClass(int day)
{
var targetDay = new DateTime(CurrentMonth.Year, CurrentMonth.Month, day);
if (SelectedDays.Contains(targetDay))
{
return "btn-primary";
}
else if (SelectableDays.Select(p => p.Date).Contains(targetDay.Date))
{
return "btn-outline-primary";
}
return string.Empty;
}
public void ToggleDate(int day)
{
var clickedDate = new DateTime(CurrentMonth.Year, CurrentMonth.Month, day);
if (IsSelectable(clickedDate) == false)
return;
if (SelectedDays.Contains(clickedDate))
{
SelectedDays.Remove(clickedDate);
}
else
{
SelectedDays.Add(clickedDate);
}
SelectedDaysChanged.InvokeAsync(SelectedDays);
}
public void ChangeMonth(int addMonths)
{
CurrentMonth = CurrentMonth.AddMonths(addMonths);
CurrentMonthChanged.InvokeAsync(CurrentMonth);
}
}
and. my parent page use like this.
first
<Calendar SelectableDays="SelectableDays"
@bind-SelectedDays="SelectedDays"
SelectedDaysChanged="SelectedDaysChanged"
></Calendar>
@code{
public List<DateTime> SelectableDays { get; set; } = new List<DateTime>() { new DateTime(2020, 04, 03) };
public List<DateTime> SelectedDays { get; set; } = new List<DateTime>();
public int SelectListCount { get; set; }
public void SelectedDaysChanged(List<DateTime> selectList)
{
SelectListCount = selectList.Count;
}
}
i got this message. The component parameter 'SelectedDaysChanged' is used two or more times for this component. Parameters must be unique (case-insensitive). The component parameter 'SelectedDaysChanged' is generated by the '@bind-SelectedDays' directive attribute.
so i changed my method. like this.
<Calendar SelectableDays="SelectableDays"
@bind-SelectedDays="SelectedDays"></Calendar>
@code{
public List<DateTime> SelectableDays { get; set; } = new List<DateTime>() { new DateTime(2020, 04, 03) };
public List<DateTime> _selectedDays = new List<DateTime>();
public List<DateTime> SelectedDays
{
get { return _selectedDays; }
set
{
if (_selectedDays != value)
_selectedDays = value;
SelectListCount = _selectedDays.Count;
}
}
public int SelectListCount { get; set; }
}
this is look like i want.
but in SelectedDays's Setter.
if (_selectedDays != value)
is always false.
this mean _selectedDays set before into this setter.
what is problem?
how can i get SelectedDays changed callback event?
i must make other property? like OnChangedSelectedDays, and call in Calendar component's ToggleDate method?
this is my full source code.
index.razor
@page "/"
<Calendar SelectableDays="SelectableDays"
@bind-SelectedDays="SelectedDays"></Calendar>
@code{
public List<DateTime> SelectableDays { get; set; } = new List<DateTime>() { new DateTime(2020, 04, 03) };
public List<DateTime> _selectedDays = new List<DateTime>();
[Parameter]
public List<DateTime> SelectedDays
{
get { return _selectedDays; }
set
{
if (_selectedDays != value)
_selectedDays = value;
SelectListCount = _selectedDays.Count;
}
}
public int SelectListCount { get; set; }
}
Calendar.razor
<div class="table-responsive-sm">
<table class="table table-sm text-center calendar">
<thead>
<tr>
<th colspan="7">
<button @onclick="(e=> ChangeMonth(-1))" class="btn btn-link">
<
</button>
@($"{CurrentMonth:yyyy.MM}")
<button @onclick="(e=> ChangeMonth(1))" class="btn btn-link">
>
</button>
</th>
</tr>
<tr>
<th scope="col">SUN</th>
<th scope="col">MON</th>
<th scope="col">TUS</th>
<th scope="col">WED</th>
<th scope="col">THU</th>
<th scope="col">FRI</th>
<th scope="col">SAT</th>
</tr>
</thead>
<tbody>
@{
var i = 0;
var prevLastDay = CurrentMonth.AddDays(-1).Day;
}
@for (var row = 0; row < 5; row++)
{
<tr>
@for (var col = 0; col < 7; col++)
{
if (i < (int)StartDayOfWeek)
{
<td style="color:gray;">
@(prevLastDay - ((int)StartDayOfWeek - i))
</td>
}
else if (i >= (DaysInMonth + (int)StartDayOfWeek))
{
<td style="color:gray;">@(i - (DaysInMonth + (int)StartDayOfWeek) + 1)</td>
}
else
{
var day = i - (int)StartDayOfWeek + 1;
<td>
<button class="btn btn-sm btn-block @(DayClass(day))" @onclick="(e=> ToggleDate(day))">
@(day)
</button>
</td>
}
i++;
}
</tr>
}
</tbody>
</table>
</div>
@code {
/// <summary>
/// Current Month
/// </summary>
[Parameter]
public DateTime CurrentMonth { get; set; } = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
/// <summary>
/// Start Day Of First Day In Current Month
///</summary>
private DayOfWeek StartDayOfWeek => CurrentMonth.DayOfWeek;
// I've changed the SelectedDays property in the Calendar component
// This is a parameter property, and it leads to subtle errors
// when used in your code as a local variable. Instead, define a
// local variable to get and set values from it, as I do in the
// ToggleDate method below.
private List<DateTime> _selectedDays = new List<DateTime>();
[Parameter]
public List<DateTime> SelectedDays
{
get { return _selectedDays; }
set
{
if (_selectedDays != value)
_selectedDays = value;
if (SelectedDaysChanged.HasDelegate)
{
SelectedDaysChanged.InvokeAsync(value);
}
}
}
///// <summary>
///// Selected Day List
///// </summary>
//[Parameter]
//public List<DateTime> SelectedDays { get; set; } = new List<DateTime>();
[Parameter]
public EventCallback<List<DateTime>> SelectedDaysChanged { get; set; }
/// <summary>
/// Selectable Day List
/// </summary>
[Parameter]
public List<DateTime> SelectableDays { get; set; } = new List<DateTime>();
[Parameter]
public EventCallback<DateTime> CurrentMonthChanged { get; set; }
private int DaysInMonth => DateTime.DaysInMonth(CurrentMonth.Year, CurrentMonth.Month);
protected override void OnParametersSet()
{
base.OnParametersSet();
CurrentMonth = CurrentMonth.AddDays(CurrentMonth.Day * -1 + 1);
}
protected override void OnInitialized()
{
}
public bool IsSelectable(DateTime date)
{
return SelectableDays.Select(p => p.Date).Contains(date.Date);
}
public string DayClass(int day)
{
var targetDay = new DateTime(CurrentMonth.Year, CurrentMonth.Month, day);
if (SelectedDays.Contains(targetDay))
{
return "btn-primary";
}
else if (SelectableDays.Select(p => p.Date).Contains(targetDay.Date))
{
return "btn-outline-primary";
}
return string.Empty;
}
public void ToggleDate(int day)
{
var clickedDate = new DateTime(CurrentMonth.Year,
CurrentMonth.Month, day);
if (IsSelectable(clickedDate) == false)
return;
var selectedDays = SelectedDays;
if (selectedDays.Contains(clickedDate))
{
selectedDays.Remove(clickedDate);
}
else
{
selectedDays.Add(clickedDate);
}
// Update the SelectedDays property
SelectedDays = selectedDays;
//var clickedDate = new DateTime(CurrentMonth.Year, CurrentMonth.Month, day);
//if (IsSelectable(clickedDate) == false)
// return;
//if (SelectedDays.Contains(clickedDate))
//{
// SelectedDays.Remove(clickedDate);
//}
//else
//{
// SelectedDays.Add(clickedDate);
//}
//SelectedDaysChanged.InvokeAsync(SelectedDays);
}
public void ChangeMonth(int addMonths)
{
CurrentMonth = CurrentMonth.AddMonths(addMonths);
CurrentMonthChanged.InvokeAsync(CurrentMonth);
}
}
complete source.
index.razor
@page "/"
<Calendar SelectableDays="SelectableDays"
@bind-SelectedDays="SelectedDays"></Calendar>
<div>
@SelectListCount
</div>
@code{
public List<DateTime> SelectableDays { get; set; } = new List<DateTime>() { new DateTime(2020, 04, 03) };
public List<DateTime> _selectedDays = new List<DateTime>();
[Parameter]
public List<DateTime> SelectedDays
{
get { return _selectedDays; }
set
{
if (_selectedDays != value)
_selectedDays = value;
SelectListCount = _selectedDays.Count;
}
}
public int SelectListCount { get; set; }
}
calendar.razor
<div class="table-responsive-sm">
<table class="table table-sm text-center calendar">
<thead>
<tr>
<th colspan="7">
<button @onclick="(e=> ChangeMonth(-1))" class="btn btn-link">
<
</button>
@($"{CurrentMonth:yyyy.MM}")
<button @onclick="(e=> ChangeMonth(1))" class="btn btn-link">
>
</button>
</th>
</tr>
<tr>
<th scope="col">SUN</th>
<th scope="col">MON</th>
<th scope="col">TUS</th>
<th scope="col">WED</th>
<th scope="col">THU</th>
<th scope="col">FRI</th>
<th scope="col">SAT</th>
</tr>
</thead>
<tbody>
@{
var i = 0;
var prevLastDay = CurrentMonth.AddDays(-1).Day;
}
@for (var row = 0; row < 5; row++)
{
<tr>
@for (var col = 0; col < 7; col++)
{
if (i < (int)StartDayOfWeek)
{
<td style="color:gray;">
@(prevLastDay - ((int)StartDayOfWeek - i))
</td>
}
else if (i >= (DaysInMonth + (int)StartDayOfWeek))
{
<td style="color:gray;">@(i - (DaysInMonth + (int)StartDayOfWeek) + 1)</td>
}
else
{
var day = i - (int)StartDayOfWeek + 1;
<td>
<button class="btn btn-sm btn-block @(DayClass(day))" @onclick="@((e) => ToggleDate(day))">
@(day)
</button>
</td>
}
i++;
}
</tr>
}
</tbody>
</table>
</div>
@code {
/// <summary>
/// Current Month
/// </summary>
[Parameter]
public DateTime CurrentMonth { get; set; } = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
/// <summary>
/// Start Day Of First Day In Current Month
///</summary>
private DayOfWeek StartDayOfWeek => CurrentMonth.DayOfWeek;
[Parameter]
public List<DateTime> SelectedDays { get; set; }
///// <summary>
///// Selected Day List
///// </summary>
//[Parameter]
//public List<DateTime> SelectedDays { get; set; } = new List<DateTime>();
[Parameter]
public EventCallback<List<DateTime>> SelectedDaysChanged { get; set; }
/// <summary>
/// Selectable Day List
/// </summary>
[Parameter]
public List<DateTime> SelectableDays { get; set; }
[Parameter]
public EventCallback<DateTime> CurrentMonthChanged { get; set; }
private int DaysInMonth => DateTime.DaysInMonth(CurrentMonth.Year, CurrentMonth.Month);
protected override void OnParametersSet()
{
base.OnParametersSet();
CurrentMonth = CurrentMonth.AddDays(CurrentMonth.Day * -1 + 1);
}
protected override void OnInitialized()
{
}
public bool IsSelectable(DateTime date)
{
return SelectableDays.Select(p => p.Date).Contains(date.Date);
}
public string DayClass(int day)
{
var targetDay = new DateTime(CurrentMonth.Year, CurrentMonth.Month, day);
if (SelectedDays.Contains(targetDay))
{
return "btn-primary";
}
else if (SelectableDays.Select(p => p.Date).Contains(targetDay.Date))
{
return "btn-outline-primary";
}
return string.Empty;
}
public void ToggleDate(int day)
{
var clickedDate = new DateTime(CurrentMonth.Year,
CurrentMonth.Month, day);
//if (IsSelectable(clickedDate) == false)
// return;
var tempSelectedDays = SelectedDays.Select(p => p).ToList(); // add here
if (tempSelectedDays.Contains(clickedDate))
{
tempSelectedDays.Remove(clickedDate);
}
else
{
tempSelectedDays.Add(clickedDate);
}
SelectedDaysChanged.InvokeAsync(tempSelectedDays);
}
public void ChangeMonth(int addMonths)
{
CurrentMonth = CurrentMonth.AddMonths(addMonths);
CurrentMonthChanged.InvokeAsync(CurrentMonth);
}
}
OK, this is the culprit:
//if (IsSelectable(clickedDate) == false)
// return;
The following code is working:
@page "/"
<Calendar SelectableDays="SelectableDays"
@bind-SelectedDays="@SelectedDays"></Calendar>
@code{
public List<DateTime> SelectableDays { get; set; } = new
List<DateTime>() { new DateTime(2020, 04, 03) };
private List<DateTime> _selectedDays = new List<DateTime>();
[Parameter]
public List<DateTime> SelectedDays
{
get { return _selectedDays; }
set
{
if (_selectedDays != value)
_selectedDays = value;
SelectListCount = _selectedDays.Count;
}
}
public int SelectListCount { get; set; }
}
<div class="table-responsive-sm">
<table class="table table-sm text-center calendar">
<thead>
<tr>
<th colspan="7">
<button @onclick="(e=> ChangeMonth(-1))" class="btn btn-link">
<
</button>
@($"{CurrentMonth:yyyy.MM}")
<button @onclick="(e=> ChangeMonth(1))" class="btn btn-link">
>
</button>
</th>
</tr>
<tr>
<th scope="col">SUN</th>
<th scope="col">MON</th>
<th scope="col">TUS</th>
<th scope="col">WED</th>
<th scope="col">THU</th>
<th scope="col">FRI</th>
<th scope="col">SAT</th>
</tr>
</thead>
<tbody>
@{
var i = 0;
var prevLastDay = CurrentMonth.AddDays(-1).Day;
}
@for (var row = 0; row < 5; row++)
{
<tr>
@for (var col = 0; col < 7; col++)
{
if (i < (int)StartDayOfWeek)
{
<td style="color:gray;">
@(prevLastDay - ((int)StartDayOfWeek - i))
</td>
}
else if (i >= (DaysInMonth + (int)StartDayOfWeek))
{
<td style="color:gray;">@(i - (DaysInMonth + (int)StartDayOfWeek) + 1)</td>
}
else
{
var day = i - (int)StartDayOfWeek + 1;
<td>
<button class="btn btn-sm btn-block @(DayClass(day))" @onclick="@((e) => ToggleDate(day))">
@(day)
</button>
</td>
}
i++;
}
</tr>
}
</tbody>
</table>
</div>
@code {
/// <summary>
/// Current Month
/// </summary>
[Parameter]
public DateTime CurrentMonth { get; set; } = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
/// <summary>
/// Start Day Of First Day In Current Month
///</summary>
private DayOfWeek StartDayOfWeek => CurrentMonth.DayOfWeek;
[Parameter]
public List<DateTime> SelectedDays { get; set; }
///// <summary>
///// Selected Day List
///// </summary>
//[Parameter]
//public List<DateTime> SelectedDays { get; set; } = new List<DateTime>();
[Parameter]
public EventCallback<List<DateTime>> SelectedDaysChanged { get; set; }
/// <summary>
/// Selectable Day List
/// </summary>
[Parameter]
public List<DateTime> SelectableDays { get; set; }
[Parameter]
public EventCallback<DateTime> CurrentMonthChanged { get; set; }
private int DaysInMonth => DateTime.DaysInMonth(CurrentMonth.Year, CurrentMonth.Month);
protected override void OnParametersSet()
{
base.OnParametersSet();
CurrentMonth = CurrentMonth.AddDays(CurrentMonth.Day * -1 + 1);
}
protected override void OnInitialized()
{
}
public bool IsSelectable(DateTime date)
{
return SelectableDays.Select(p => p.Date).Contains(date.Date);
}
public string DayClass(int day)
{
var targetDay = new DateTime(CurrentMonth.Year, CurrentMonth.Month, day);
if (SelectedDays.Contains(targetDay))
{
return "btn-primary";
}
else if (SelectableDays.Select(p => p.Date).Contains(targetDay.Date))
{
return "btn-outline-primary";
}
return string.Empty;
}
public void ToggleDate(int day)
{
var clickedDate = new DateTime(CurrentMonth.Year,
CurrentMonth.Month, day);
//if (IsSelectable(clickedDate) == false)
// return;
Console.WriteLine($"ToggleDate {day}");
if (SelectedDays.Contains(clickedDate))
{
SelectedDays.Remove(clickedDate);
}
else
{
SelectedDays.Add(clickedDate);
}
SelectedDaysChanged.InvokeAsync(SelectedDays);
}
public void ChangeMonth(int addMonths)
{
CurrentMonth = CurrentMonth.AddMonths(addMonths);
CurrentMonthChanged.InvokeAsync(CurrentMonth);
}
}
Nice calendar, when you finish post here the code;)
Hope this helps..
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.