Reputation: 3
I'm trying to realize Blazor's InputCheckBox with Dictionary<string, bool> model. In fact I want to realize a set of CheckBoxes in foreach cycle. And while I have at the first line of the cycle property with {get; set;} in InputCheckBox (as shown in my Visual Studio's screenchort) it turns to readonly property with only {get;}
@page "/select-props"
@{
CsvContent headers = new();
}
<h3>Properties picker</h3>
<div class="container container-fluid overflow-auto">
<table class="table overflow-auto">
<EditForm Model="headers">
@foreach (var item in headers.Headers)
{
<tr class="row ">
@if (item.Key is not null)
{
<td scope="col" class="col border border-1 border-secondary">
<InputCheckbox class="btn-check" @bind-Value="item.Value">
@item.Key
</InputCheckbox>
</td>
}
</tr>
}
<button class="btn btn-info" type="submit">
Submit
</button>
</EditForm>
</table>
</div>
@code {
}
That is the model class:
public class CsvContent
{
static Dictionary<int, char> divider = new() { { 0, ',' }, { 1, ';' }, { 2, '\t' } };
public static List<List<string>?> FileContent { get; set; }
public Dictionary<string, bool>? Headers { get; set; }
public static async Task/*<List<List<string>>*/ ReadCsvAsync(string path, int divederCode = 2)
{
FileContent = new List<List<string>?>();
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
using (StreamReader reader = new StreamReader(path, System.Text.Encoding.GetEncoding(1251)))
{
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
List<string> cells = new();
cells.AddRange(line.Split(divider[divederCode]));
FileContent.Add(cells);
}
}
}
public CsvContent()
{
if (FileContent is not null)
{
foreach (var item in FileContent)
Headers.TryAdd(item.ElementAt(0), false);
}
}
}
I can't relize why my dictionary value turn to readonly, please help...
Upvotes: 0
Views: 1046
Reputation: 21
Workaround for binding to Dictionary<string, bool>:
@foreach (var item in headers.Headers)
{
bool boolVal = headers.Headers[item.Key];
...
<InputCheckbox Value="boolVal" ValueExpression="@(() => boolVal)" ValueChanged="@(b => headers.Headers[item.Key] = b)">
@item.Key
</InputCheckbox>
...
}
It work in ASP.Net 6.0.
Upvotes: 2
Reputation: 30410
As eluded to in the other answer and comments, KeyValuePair
objects are readonly .
You can move away from the Dictionary, and use a List
of a header state object. You are almost certainly doing this in the context of some sort of Grid control, so will be using the Header State elsewhere.
Here's a Demo page with the object classes included in the page.
Note the null reference warning goes away by removing the nullable ?
in the declaration and declaring a default value for Headers
.
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<h3>Properties picker</h3>
<EditForm Model="headers">
@foreach (var item in headers.Headers)
{
<div class="form-check mb-2">
<InputCheckbox class="form-check-input" @bind-Value=item.State />
<label class="form-check-label">@item.Name</label>
</div>
}
</EditForm>
<div class="bg-dark text-white m-2 p-2">
@foreach (var item in headers.Headers)
{
<pre>@item.Name : @item.State</pre>
}
</div>
@code {
private Model headers = new();
protected override Task OnInitializedAsync()
{
headers.Headers.Add(new("UK", false));
headers.Headers.Add(new("France", false));
headers.Headers.Add(new("Spain", false));
return Task.CompletedTask;
}
public class Model
{
// The null reference error goes away by declaring a default value for Headers
public List<HeaderData> Headers { get; set; } = new();
}
public class HeaderData
{
public string Name { get; init; }
public bool State { get; set; }
public HeaderData(string name, bool state = false)
{
this.Name = name;
this.State = state;
}
}
}
Upvotes: 0
Reputation: 1375
KeyValuePair.Value
is readonly, there is not much you can do about it. However, I believe you can bind it going through the dictionary directly:
@bind-Value="headers.Headers[item.Key]"
.
Upvotes: 0