MudBlazor Mudtable RowEditing Datetime - blazor-server-side

I use from mudblazor the MudTable. It displays the data perfectly.
I like to edit it inline. In my model there is a DateTime field I want to edit and set.
After some juggling around, I see a datepicker, a timepicker, but I can't seem to figure out how to edit this inline as a legal date and time format and combine them back to the data-sourcefield.
Can you help me with some samplecode to achieve that.
Thank you.

Inside the <MudTd> tag, add the MudDatePicker and MudTimePicker:
<MudTd>
<MudDatePicker
Date="#context.DateTime.Date"
DateChanged="#(d => this.DateChanged(d.Value, context))"/>
<MudTimePicker
Time="#context.DateTime.TimeOfDay"
TimeChanged="#(t => this.TimeChanged(t.Value, context))"/>
</MudTd>
and implement the DateChanged(...) and TimeChanged(...) in your own code.
A demo:
#page "/"
<MudTable Items="#this.elements">
<ToolBarContent>
<MudText Typo="Typo.h6">Elements</MudText>
</ToolBarContent>
<HeaderContent>
<MudTh>Id</MudTh>
<MudTh>Name</MudTh>
<MudTh>DateTime</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd>#context.Id</MudTd>
<MudTd>#context.Name</MudTd>
<MudTd>
<MudDatePicker Date="#context.DateTime.Date" DateChanged="#(d => this.DateChanged(d.Value, context))"/>
<MudTimePicker Time="#context.DateTime.TimeOfDay" TimeChanged="#(t => this.TimeChanged(t.Value, context))"/>
</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager />
</PagerContent>
</MudTable>
<MudText Color="Color.Primary">#this.log</MudText>
#code {
private string log = string.Empty;
private List<Element> elements = new();
protected override void OnInitialized()
{
this.elements = new List<Element>
{
new() { Id = 1, Name = "First", DateTime = DateTime.UtcNow - TimeSpan.FromDays(1) },
new() { Id = 2, Name = "Second", DateTime = DateTime.UtcNow - TimeSpan.FromDays(2) },
new() { Id = 3, Name = "Third", DateTime = DateTime.UtcNow - TimeSpan.FromDays(3) },
};
}
public class Element
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime DateTime { get; set; }
}
private void DateChanged(DateTime date, Element element)
{
this.SetDateTime(date, element.DateTime.TimeOfDay, element);
}
private void TimeChanged(TimeSpan time, Element element)
{
this.SetDateTime(element.DateTime.Date, time, element);
}
private void SetDateTime(DateTime date, TimeSpan time, Element element)
{
element.DateTime = new DateTime(date.Year, date.Month, date.Day, time.Hours, time.Minutes, time.Seconds);
this.log = $"New datetime for element with Id {element.Id}: {element.DateTime}";
}
}
Try it online: https://try.mudblazor.com/snippet/caGROlvFgrXENaMD

Related

Blazor binding parent/child dropdown controls fails to set default value on child control

On a parent/child dropdown scenario, I'm trying to display a default value for the child dropdown each time the parent dropdown is updated.
The code does the job, since it updates the sample label, but the child dropdown does not display anything.
For simplicity I am demonstrating the issue with a country/zone pair of select controls.
Initial render correctly shows the default country and the default zone of the country.
Updating the country sets the new default zone on the label but the zones select turns blank:
#page "/test"
<select #bind="#CountryName">
#foreach (var country in Countries)
{
<option>#country.Name</option>
}
</select>
<select #bind="#ZoneName">
#foreach (string zone in Zones)
{
<option>#zone</option>
}
</select>
<div>Selected country: #CountryName</div>
<div>Selected zone: #ZoneName</div>
#code {
private List<Country> Countries;
private List<String> Zones = new();
private string countryName;
private string CountryName
{
get => countryName;
set
{
countryName = value;
var country = Countries.First(x => x.Name == value);
Zones = country.Zones.Select(x => x.Name).ToList();
ZoneName = country.DefaultZoneName;
}
}
private string zoneName;
private string ZoneName
{
get => zoneName;
set
{
zoneName = value;
}
}
protected override void OnInitialized()
{
//data factory
var barcelona = new Zone() { Name = "Barcelona" };
var madrid = new Zone() { Name = "Madrid" };
var spain = new Country() { Name = "Spain" };
spain.Zones.Add(barcelona);
spain.Zones.Add(madrid);
spain.DefaultZoneName = spain.Zones.Last().Name;;
var açores = new Zone() { Name = "Açores" };
var algarve = new Zone() { Name = "Algarve" };
var portugal = new Country() { Name = "Portugal" };
portugal.Zones.Add(açores);
portugal.Zones.Add(algarve);
portugal.DefaultZoneName = portugal.Zones.Last().Name;
Countries = new List<Country>();
Countries.Add(spain);
Countries.Add(portugal);
CountryName = Countries.Last().Name;
base.OnInitialized();
}
//models
public class Country
{
public string Name { get; set; }
public List<Zone> Zones { get; set; } = new();
public string DefaultZoneName { get; set; }
}
public class Zone
{
public string Name { get; set; }
}
}
The problem is that set method on variable doesn't cause the page to re-render: automatic re-render occurs with a Task handling an #event, and forced re-render occurs with StateHasChanged.
You are trying to use set method because 2-way binding on the select consumes the #onchange event, so you have no way to do anything when a value is selected. However, this is a trap. Blazor allows C# boolean for selected (and also for other things like disabled or hidden).
You already took some time to set up your data nicely, so you can track selection by reference, not by copying the string values of names to new variables.
I think the following is an improvement. I hope it helps you, as this same situation will come up very often in Blazor:
#page "/"
<select #onchange="(args) => SelectedCountry = Countries.First(x => x.Name==args.Value?.ToString())">
#foreach (var country in Countries)
{
<option selected="#(country == SelectedCountry)" >#country.Name</option>
}
</select>
<select #onchange="(args) => SelectedCountry.SelectedZone = SelectedCountry.Zones.First(x => x.Name==args.Value?.ToString())">
#foreach (var zone in SelectedCountry.Zones)
{
<option selected="#(zone == SelectedCountry.SelectedZone)">#zone.Name</option>
}
</select>
<div>Selected country: #SelectedCountry.Name</div>
<div>Selected zone: #SelectedCountry?.SelectedZone?.Name</div>
#code {
private List<Country> Countries = new();
private Country SelectedCountry = new();
protected override void OnInitialized()
{
//data factory
var barcelona = new Zone() { Name = "Barcelona" };
var madrid = new Zone() { Name = "Madrid" };
var spain = new Country() { Name = "Spain" };
spain.Zones.Add(barcelona);
spain.Zones.Add(madrid);
spain.SelectedZone = spain.Zones.Last();
var açores = new Zone() { Name = "Açores" };
var algarve = new Zone() { Name = "Algarve" };
var portugal = new Country() { Name = "Portugal" };
portugal.Zones.Add(açores);
portugal.Zones.Add(algarve);
portugal.SelectedZone = portugal.Zones.Last();
Countries = new List<Country>();
Countries.Add(spain);
Countries.Add(portugal);
SelectedCountry = portugal;
}
//models
public class Country
{
public string Name { get; set; }
public List<Zone> Zones { get; set; } = new();
public Zone? SelectedZone;
}
public class Zone
{
public string Name { get; set; }
}
}

Using NUnit testing with C# Collection Class Library project

/Using NUnit testing with C# Collection Class Library project
I am not able to figure out the TestFixture in this code
any help will be a great help
I have a below Test Class/
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using ScoringExercise;
using ScoringExercise.Entities;
namespace ScoringExerciseTests
{
[TestFixture]
public class ScoringTests
{
readonly List<MultiChoiceItem> _assessmentItems;
public ScoringTests()
{
// Assessment items
_assessmentItems = new List<MultiChoiceItem>
{
new MultiChoiceItem()
{
ItemText = "Which city is the capital of Sweden?",
Options = new string[] {"Helsinki", "Stockholm", "Malmö", "Oslo"},
CorrectAnswerIndex = 1,
MarksAwardedIfCorrect = 1
},
new MultiChoiceItem()
{
ItemText = "Which of these cheeses normally has large round holes?",
Options = new string[] {"Emmental", "Feta", "Danish Blue", "Gruyere"},
CorrectAnswerIndex = 0,
MarksAwardedIfCorrect = 1
},
new MultiChoiceItem()
{
ItemText = "Which of the following is not a root vegetable?",
Options = new string[] {"Carrot", "Parsnip", "Turnip", "Shallot"},
CorrectAnswerIndex = 3,
MarksAwardedIfCorrect = 4
},
new MultiChoiceItem()
{
ItemText = "What colour is the outmost archery target ring?",
Options = new string[] {"White", "Yellow", "Red", "Black"},
CorrectAnswerIndex = 0,
MarksAwardedIfCorrect = 1
},
new MultiChoiceItem()
{
ItemText = "What is the chemical symbol for silver?",
Options = new string[] {"Au", "Sr", "Si", "Ag"},
CorrectAnswerIndex = 3,
MarksAwardedIfCorrect = 2
}
};
}
[Test]
public void AllCorrect()
{
// create test data where all items have corresponding responses
// and all responses are correct
Dictionary<int, int> responses = new Dictionary<int, int>();
int i = 0;
foreach (MultiChoiceItem item in _assessmentItems)
{
responses.Add(i, item.CorrectAnswerIndex);
i++;
}
// check that actual results are in line with expected results
AssessmentResults expected = new AssessmentResults()
{
ItemsAttempted = _assessmentItems.Count,
ItemsCorrect = _assessmentItems.Count,
TotalMarksAwarded = _assessmentItems.Sum(item => item.MarksAwardedIfCorrect)
};
AssessmentResults actual = ScoringEngine.GetResults(_assessmentItems, responses);
AssertValueEquality(expected, actual);
}
[Test]
public void AllWrong()
{
// create test data where all items have corresponding responses
// and all responses are wrong
Dictionary<int, int> responses = new Dictionary<int, int>();
int i = 0;
foreach (MultiChoiceItem item in _assessmentItems)
{
if ((item.CorrectAnswerIndex + 1) < item.Options.Length)
responses.Add(i, item.CorrectAnswerIndex + 1);
else
responses.Add(i, item.CorrectAnswerIndex - 1);
i++;
}
// check that actual results are in line with expected results
AssessmentResults expected = new AssessmentResults()
{
ItemsAttempted = responses.Count,
ItemsCorrect = 0,
TotalMarksAwarded = 0
};
AssessmentResults actual = ScoringEngine.GetResults(_assessmentItems, responses);
AssertValueEquality(expected, actual);
}
private void AssertValueEquality(AssessmentResults expected, AssessmentResults actual)
{
CollectionAssert.AreEqual(
new int[] { expected.ItemsAttempted, expected.ItemsCorrect,
expected.TotalMarksAwarded },
new int[] { actual.ItemsAttempted, actual.ItemsCorrect,
actual.TotalMarksAwarded }
);
}
}
}
/How can I implement GetResults method in my Class Library project which is as below
I am not able to figure out the TestFixture in this code
any help will be a great help/
using System.Collections.Generic;
using ScoringExercise.Entities;
using System.Linq;
using System.Collections;
namespace ScoringExercise
{
public static class ScoringEngine
{
/// <summary>
/// Calculates the results of an assessment based upon the test content and candidate
/// responses.
/// </summary>
public static AssessmentResults GetResults(List<MultiChoiceItem> multiChoiceItems,
Dictionary<int, int> responses)
{
//return null;
}
}
}
namespace ScoringExercise.Entities
{
/// <summary>
/// Represents a single multi-choice item in an assessment
/// </summary>
public class MultiChoiceItem
{
// the text associated with the item aka the question
public string ItemText { get; set; }
// the option strings from which the candidate chooses a response
public string[] Options { get; set; }
// the index of the correct answer from within the Options array
public int CorrectAnswerIndex { get; set; }
// the number of marks awarded if the correct response is chosen
public int MarksAwardedIfCorrect { get; set; }
}
}
namespace ScoringExercise.Entities
{
/// <summary>
/// Represents the results of a single assessment instance
/// </summary>
public class AssessmentResults
{
public int ItemsAttempted { get; set; }
public int ItemsCorrect { get; set; }
public int TotalMarksAwarded { get; set; }
}
}
public static AssessmentResults GetResults(List<MultiChoiceItem> multiChoiceItems, Dictionary<int, int> responses)
{
int i = 0;
int ItemsCorrect = 0;
int TotalMarksAwarded = 0;
foreach (var item in multiChoiceItems.Where(c => responses.ContainsKey(c.CorrectAnswerIndex)))
{
if (item.CorrectAnswerIndex == responses[i])
{
ItemsCorrect++;
TotalMarksAwarded += item.MarksAwardedIfCorrect;
}
i++;
}
return new AssessmentResults
{
ItemsAttempted = responses.Count,
ItemsCorrect = ItemsCorrect,
TotalMarksAwarded = TotalMarksAwarded
};
}
}

Value type field required in Razor View

I have an enum type field called Title.
[Serializable]
public enum Title
{
NotSet,
Miss = 4,
Mr = 1,
Mrs = 3,
Ms = 2
}
I want to bind a property of type Title to the Razor View but I don't want it to be a required field. However, on tabbing out or OnBlur, it is showing as required, although I have not specified this as required.
Is there any way I can get around this?
create
namespace YourApplicationName.Helper
{
public class ModelValueListProvider : IEnumerable<SelectListItem>
{
List<KeyValuePair<string, string>> innerList = new List<KeyValuePair<string, string>>();
public static readonly ModelValueListProvider TitleList = new TitleListProvider();
protected void Add(string value, string text)
{
string innerValue = null, innerText = null;
if (value != null)
innerValue = value.ToString();
if (text != null)
innerText = text.ToString();
if (innerList.Exists(kvp => kvp.Key == innerValue))
throw new ArgumentException("Value must be unique", "value");
innerList.Add(new KeyValuePair<string, string>(innerValue, innerText));
}
public IEnumerator<SelectListItem> GetEnumerator()
{
return new ModelValueListProviderEnumerator(innerList.GetEnumerator());
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private struct ModelValueListProviderEnumerator : IEnumerator<SelectListItem>
{
private IEnumerator<KeyValuePair<string, string>> innerEnumerator;
public ModelValueListProviderEnumerator(IEnumerator<KeyValuePair<string, string>> enumerator)
{
innerEnumerator = enumerator;
}
public SelectListItem Current
{
get
{
var current = innerEnumerator.Current;
return new SelectListItem { Value = current.Key, Text = current.Value };
}
}
public void Dispose()
{
try
{
innerEnumerator.Dispose();
}
catch (Exception)
{
}
}
object System.Collections.IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
return innerEnumerator.MoveNext();
}
public void Reset()
{
innerEnumerator.Reset();
}
}
private class TitleListProvider : ModelValueListProvider
{
public TitleListProvider (string defaultText = null)
{
if (!string.IsNullOrEmpty(defaultText))
Add(string.Empty, defaultText);
Add(Title.NotSet, "NotSet");
Add(Title.Miss , "Miss");
Add(Title.Mr , "Mr");
Add(Title.Mrs , "Mrs");
Add(Title.MS, "MS");
}
public void Add(Title value, string text)
{
Add(value.ToString("d"), text);
}
}
}
}
in your model
public Title? Titleformation { get; set; }
public string[] SelectedTitle { get; set; }
in your view, also add the name space to your view
#using YourApplicationName.Helper;
#Html.ListBoxFor(m => m.SelectedTitle , new SelectList(ModelValueListProvider.TitleList, "Value", "Text"))
hope this help you
Enums require values, and cannot be null (aka not set) despite what someone commented above. What I do for salutations is have a "none" member of the enum, and whenever I print this out, I just check in the code to see if the value of the enum is > 0 (aka, the none option) and don't print it.
public enum Salutation { none,
[Description("Mr.")] Mr,
[Description("Mrs.")] Mrs,
[Description("Ms.")]Ms,
[Description("Miss")] Miss }
Use a class rather than enum ie:
public class Title
{
NotSet;
Miss = 4;
Mr = 1;
Mrs = 3;
Ms = 2;
}

Using DateTime object as DataMember?

I need to send in my web service some information about the time + date .
So i want to use the DateTime.
Can i define the DateTime as DataMember ?
I try to define it as as datamember - but i got an exception ( catastrophic failure )
Create new WCFDate class, and this class outputs a string in a set format, this allows it to be easily read by what ever needs to. Then replace all of Ur DateTimes with WCFDate.
public class WCFDate
{
public static string DateTimeFormat = "yyyy-MM-dd hh:mm:ss zz";
public string Data { get; set; }
public WCFDate() { }
public WCFDate(string data)
{
Data = data;
}
public WCFDate(DateTime date)
{
Data = date.ToString(DateTimeFormat);
}
public WCFDate(DateTime? date)
{
if (date.HasValue)
{
Data = date.Value.ToString(DateTimeFormat);
}
}
public bool HasDate
{
get
{
return !string.IsNullOrWhiteSpace(Data);
}
}
public DateTime GetDate()
{
try
{
return DateTime.ParseExact(Data, DateTimeFormat, CultureInfo.CurrentCulture);
}
catch
{
return new DateTime();
}
}

How do I test "Parameters Passed In Final Call" using RhinoMocks?

What's the best way in Rhino Mocks to test that a particular parameter is passed on the FINAL call to a method? Eg mockview.SetSomething(myObj) might be called any number of times by mockview.Init, but I want to test that the last time it's called as mockview.SetSomething(inParticular).
Now I know I can use GetArgumentsForCallsMadeOn with this, but my problem is that it doesn't work if I've subsequently changed the parameter holding variable. e.g
public interface IView
{
void SetSomething(ViewData data);
}
public class ViewData
{
public int Age { get; set; }
public string Name { get; set; }
public ViewData Person(int age, string name)
{
Age = age;
Name = name;
return (this);
}
}
public class WorkingPresenter
{
public void Init(IView view)
{
var data = new ViewData {Age = 1, Name = "One"};
view.SetSomething(data);
data = new ViewData {Age = 2, Name = "Two"};
view.SetSomething(data);
data = new ViewData {Age = 3, Name = "Three"};
}
}
public class NotWorkingPresenter
{
private ViewData _data;
public void Init(IView view)
{
_data = new ViewData();
view.SetSomething(_data.Person(1, "One"));
view.SetSomething(_data.Person(2, "Two"));
_data.Person(3, "Three");
}
}
then my tests are ...
[Test]
public void GetDataOfLastCall()
{
ViewData dummydata=null;
var view = MockRepository.GenerateStub<IView>();
//Approach 1 : This works
var workingPresenter = new WorkingPresenter();
workingPresenter.Init(view);
var lastCall = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata)).Count - 1;
var lastParams = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata))[lastCall];
var lastData = (ViewData)lastParams[0];
//Approach 2: This doesn't
var notWorkingPresenter = new NotWorkingPresenter();
notWorkingPresenter.Init(view);
lastCall = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata)).Count - 1;
lastParams = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(dummydata))[lastCall];
lastData = (ViewData)lastParams[0];
What I want is to verify that the last call to SetSomething was with {name="Two", age=2}. Now workingPresenter does this but wouldn't you expect notWorkingPresenter to do so too?
There must be something else going on in your code (outside of the mocking). I just threw together a few items:
public interface IView
{
void SetSomething(ViewData data);
}
public class ViewData
{
public int Age { get; set; }
public string Name { get; set; }
}
And I tested it with:
[TestMethod]
public void GetDataOfLastCall()
{
var view = MockRepository.GenerateStub<IView>();
var data = new ViewData {Age = 1, Name = "One"};
view.SetSomething(data);
data = new ViewData { Age = 2, Name = "Two" };
view.SetSomething(data);
data = new ViewData { Age = 3, Name = "Three" };
var lastCall = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(data)).Count - 1;
var lastParams = view.GetArgumentsForCallsMadeOn(v => v.SetSomething(data))[lastCall];
var lastData = (ViewData) lastParams[0];
}
And I got the values of 2 and "Two" inside the ViewData. It appears Rhino.Mocks supports what you want to do. Could you create a failing test case that shows the issue identified in your original question (where you got a reference to the most recent information)?