mirror of
https://gitee.com/ant-design-blazor/ant-design-blazor.git
synced 2024-12-05 21:47:38 +08:00
6fcdbb9ad5
* fix(module: checkbox): value binding for checkbox group
277 lines
8.7 KiB
C#
277 lines
8.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.AspNetCore.Components;
|
|
using OneOf;
|
|
|
|
namespace AntDesign
|
|
{
|
|
public partial class CheckboxGroup : AntInputComponentBase<string[]>
|
|
{
|
|
[Parameter]
|
|
public RenderFragment ChildContent { get; set; }
|
|
|
|
[Parameter]
|
|
public OneOf<CheckboxOption[], string[]> Options
|
|
{
|
|
get { return _options; }
|
|
set
|
|
{
|
|
_options = value;
|
|
_isOptionDefined = true;
|
|
if (_afterFirstRender)
|
|
{
|
|
_currentValue = GetCurrentValueFunc();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Parameter]
|
|
public CheckboxGroupMixedMode MixedMode
|
|
{
|
|
get { return _mixedMode; }
|
|
set
|
|
{
|
|
bool isChanged = _afterFirstRender && _mixedMode != value;
|
|
_mixedMode = value;
|
|
if (isChanged)
|
|
{
|
|
//were changed by RemoveItem
|
|
_indexConstructedOptionsOffset = -1; //force recalculation
|
|
_indexSetOptionsOffset = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Parameter]
|
|
public EventCallback<string[]> OnChange { get; set; }
|
|
|
|
private string[] _selectedValues;
|
|
private Func<string[]> _currentValue;
|
|
private IList<Checkbox> _checkboxItems;
|
|
private OneOf<CheckboxOption[], string[]> _options;
|
|
private OneOf<CheckboxOption[], string[]> _constructedOptions;
|
|
private bool _isOptionDefined;
|
|
private bool _afterFirstRender;
|
|
private int _indexConstructedOptionsOffset = -1;
|
|
private int _indexSetOptionsOffset = -1;
|
|
private CheckboxGroupMixedMode _mixedMode = CheckboxGroupMixedMode.ChildContentFirst;
|
|
|
|
[Parameter]
|
|
public bool Disabled { get; set; }
|
|
|
|
public CheckboxGroup()
|
|
{
|
|
ClassMapper
|
|
.Add("ant-checkbox-group")
|
|
.If("ant-checkbox-group-rtl", () => RTL);
|
|
}
|
|
|
|
internal void AddItem(Checkbox checkbox)
|
|
{
|
|
this._checkboxItems ??= new List<Checkbox>();
|
|
this._checkboxItems?.Add(checkbox);
|
|
|
|
checkbox.IsFromOptions = IsCheckboxFromOptions(checkbox);
|
|
if (!checkbox.IsFromOptions)
|
|
{
|
|
checkbox.SetValue(_selectedValues.Contains(checkbox.Label));
|
|
if (_indexConstructedOptionsOffset == -1)
|
|
_indexConstructedOptionsOffset = _checkboxItems.Count - 1;
|
|
}
|
|
else if (checkbox.IsFromOptions && _indexSetOptionsOffset == -1)
|
|
_indexSetOptionsOffset = _checkboxItems.Count - 1;
|
|
}
|
|
|
|
private bool IsCheckboxFromOptions(Checkbox checkbox)
|
|
{
|
|
if (Options.Value is not null)
|
|
{
|
|
if (ChildContent is not null)
|
|
{
|
|
return Options.Match(
|
|
opt => opt.Any(o => o.Label.Equals(checkbox.Label)),
|
|
arr => arr.Contains(checkbox.Label));
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal void RemoveItem(Checkbox checkbox)
|
|
{
|
|
this._checkboxItems?.Remove(checkbox);
|
|
if (!checkbox.IsFromOptions && _indexConstructedOptionsOffset >= 0)
|
|
_indexConstructedOptionsOffset--;
|
|
else if (checkbox.IsFromOptions && _indexSetOptionsOffset >= 0)
|
|
_indexSetOptionsOffset--;
|
|
}
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
if (ChildContent is null && MixedMode == CheckboxGroupMixedMode.ChildContentFirst)
|
|
MixedMode = CheckboxGroupMixedMode.OptionsFirst;
|
|
|
|
base.OnInitialized();
|
|
|
|
if (Value != null)
|
|
{
|
|
_selectedValues = Value;
|
|
if (Options.IsT0)
|
|
{
|
|
Options.AsT0.ForEach(opt => opt.Checked = opt.Value.IsIn(_selectedValues));
|
|
}
|
|
}
|
|
|
|
_selectedValues ??= Array.Empty<string>();
|
|
}
|
|
|
|
protected override void OnValueChange(string[] value)
|
|
{
|
|
base.OnValueChange(value);
|
|
|
|
if (Disabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_selectedValues = value;
|
|
|
|
if (Options.Value != null && Options.IsT0)
|
|
{
|
|
Options.AsT0.ForEach(x =>
|
|
{
|
|
if (!x.Disabled)
|
|
{
|
|
x.Checked = x.Value.IsIn(_selectedValues);
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
var invokeChange = false;
|
|
|
|
_checkboxItems.ForEach(x =>
|
|
{
|
|
var checkBoxValue = x.Label.IsIn(value);
|
|
if (checkBoxValue != x.Value)
|
|
{
|
|
invokeChange = true;
|
|
x.SetValue(checkBoxValue);
|
|
OnCheckboxChange(x, false);
|
|
}
|
|
});
|
|
|
|
if (invokeChange)
|
|
{
|
|
InvokeValueChange();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnAfterRender(bool firstRender)
|
|
{
|
|
if (firstRender)
|
|
{
|
|
if (ChildContent is not null && _checkboxItems.Count > 0)
|
|
{
|
|
_constructedOptions = CreateConstructedOptions();
|
|
}
|
|
_currentValue = GetCurrentValueFunc();
|
|
_afterFirstRender = true;
|
|
}
|
|
base.OnAfterRender(firstRender);
|
|
}
|
|
|
|
private OneOf<CheckboxOption[], string[]> CreateConstructedOptions()
|
|
{
|
|
if (Options.IsT0)
|
|
{
|
|
return _checkboxItems
|
|
.Where(c => !c.IsFromOptions)
|
|
.Select(c => new CheckboxOption { Label = c.Label, Value = c.Label, Checked = c.Value })
|
|
.ToArray();
|
|
}
|
|
return _checkboxItems
|
|
.Where(c => !c.IsFromOptions)
|
|
.Select(c => c.Label).ToArray();
|
|
}
|
|
|
|
private Func<string[]> GetCurrentValueFunc()
|
|
{
|
|
if (ChildContent is not null && _isOptionDefined)
|
|
{
|
|
return Options.Match<Func<string[]>>(
|
|
opt => () => opt.Where(x => x.Checked).Select(x => x.Value)
|
|
.Union(_constructedOptions.AsT0.Where(x => x.Checked).Select(x => x.Value))
|
|
.ToArray(),
|
|
arr => () => _selectedValues);
|
|
}
|
|
var workWith = (_isOptionDefined ? Options : _constructedOptions);
|
|
return workWith.Match<Func<string[]>>(
|
|
opt => () => opt.Where(x => x.Checked).Select(x => x.Value).ToArray(),
|
|
arr => () => _selectedValues);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when [checkbox change].
|
|
/// </summary>
|
|
/// <param name="checkbox">The checkbox.</param>
|
|
/// <param name="invokeOnChange">Flag for whether or not to depart for a change event.</param>
|
|
/// <returns></returns>
|
|
internal void OnCheckboxChange(Checkbox checkbox, bool invokeOnChange = true)
|
|
{
|
|
var index = _checkboxItems.IndexOf(checkbox);
|
|
int indexOffset;
|
|
OneOf<CheckboxOption[], string[]> workWith;
|
|
if (checkbox.IsFromOptions)
|
|
{
|
|
indexOffset = _indexSetOptionsOffset;
|
|
workWith = Options;
|
|
}
|
|
else
|
|
{
|
|
indexOffset = _indexConstructedOptionsOffset;
|
|
workWith = _constructedOptions;
|
|
}
|
|
|
|
|
|
workWith.Switch(opts =>
|
|
{
|
|
if (opts[index] != null)
|
|
{
|
|
opts[index].Checked = checkbox.Checked;
|
|
}
|
|
}, opts =>
|
|
{
|
|
if (checkbox.Checked && !opts[index - indexOffset].IsIn(_selectedValues))
|
|
{
|
|
_selectedValues = _selectedValues.Append(opts[index - indexOffset]);
|
|
}
|
|
else
|
|
{
|
|
_selectedValues = _selectedValues.Except(new[] { opts[index - indexOffset] }).ToArray();
|
|
}
|
|
});
|
|
|
|
if (invokeOnChange)
|
|
{
|
|
CurrentValue = _currentValue();
|
|
|
|
InvokeValueChange();
|
|
}
|
|
}
|
|
|
|
private void InvokeValueChange()
|
|
{
|
|
if (OnChange.HasDelegate)
|
|
{
|
|
OnChange.InvokeAsync(CurrentValue);
|
|
}
|
|
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
}
|