What Changed
We changed the delegate type from Action to EventCallback for the following events:
- DxButton.Click - EventCallback<MouseEventArgs>
- DxCalendar.SelectedDatesChanged - EventCallback<T>
- DxChartSeries.VisibleChanged - EventCallback<bool>
- DxCheckBox.CheckedChanged - EventCallback<T>
- DxComboBox.TextChanged - EventCallback<string>
- DxComboBox.DropDownVisibleChanged - EventCallback<bool>
- DxDateEdit.DateChanged - EventCallback<T>
- DxDateEdit.DropDownVisibleChanged - EventCallback<bool>
- DxFormLayout.ItemUpdating - EventCallback<KeyValuePair<string, object>>
- DxFormLayoutTabPages.ActiveTabIndexChanged - EventCallback<int>
- DxPager.ActivePageIndexChanged - EventCallback<int>
- DxPopup.VisibleChanged - EventCallback<bool>
- DxSpinEdit.ValueChanged - EventCallback<T>
- DxTabs.ActiveTabIndexChanged - EventCallback<int>
- DxTagBox.TagsChanged - EventCallback<IEnumerable<string>>
- DxTagBox.DropDownVisibleChanged - EventCallback<bool>
- DxTextBox.TextChanged - EventCallback<string>
Reasons for Change
In previous versions, you had to call the StateHasChanged method in an event handler to rerender a component after changes. The EventCallback delegate contains a reference to its bound component and calls the StateHasChanged method automatically. So, you no longer need to care about component rerendering and complicate your code.
Razor<DxButton ...Click="@Like">
@code {
int likes = 1;
void Like(MouseEventArgs args) {
likes++;
// InvokeAsync(StateHasChanged); You no longer need to call this method.
}
}
The *Changed events listed above now automatically update the corresponding properties if you use a two-way binding (the @bind attribute). You can simplify your code as follows:
Razor<DxSpinEdit @bind-Value="@DecimalValue"></DxSpinEdit>
@code {
// Old version:
// Decimal decimalValue = 15;
// Decimal DecimalValue { get => decimalValue;
// set { decimalValue = value; InvokeAsync(StateHasChanged); } }
// New version:
Decimal DecimalValue { get; set; } = 15;
}
The EventCallback delegate is also more convenient when you do not need to pass event parameters. Even if an event has the EventCallback<ChangeEventArgs>
signature, you can implement event handlers without parameters.
Impact on Existing Apps
These changes will affect your application in the following cases:
- If you handle an event that now uses the EventCallback<T> delegate.
Razor<DxSpinEdit Value="@NumericValue" ValueChanged="@((newValue) => OnValueChanged(newValue))" />
<DxDateEdit Date="@Date" DateChanged="@((newValue) => OnDateChanged(newValue))" />
- If you handle the DxFormLayout.ItemUpdating event.
Razor<DxFormLayout ... ItemUpdating="@((fieldName, newValue) => OnItemUpdating(fieldName, newValue))">
</DxFormLayout>
- If you handle any of the listed events in C# code via RenderTreeBuilder (instead of the Razor markup).
C#builder.OpenComponent<DxCheckBox<T>>(0);
builder.AddAttribute(1, "CheckedChanged", new Action<T>((newValue) => onValueChanged(newValue)));
How to Update Existing Apps
- If an event uses the EventCallback<T> delegate, specify the component data type explicitly.
Razor<DxSpinEdit Value="@NumericValue" ValueChanged="@((int newValue) => OnValueChanged(newValue))" />
<DxDateEdit Date="@Date" DateChanged="@((DateTime newValue) => OnDateChanged(newValue))" />
- Handle the DxFormLayout.ItemUpdating event as follows:
Razor<DxFormLayout ... ItemUpdating="@((pair) => OnItemUpdating(pair.Key, pair.Value))">
</DxFormLayout>
- Handle an event in C# code in the way shown below:
C#builder.OpenComponent<DxCheckBox<T>>(0);
builder.AddAttribute(1, "CheckedChanged", EventCallback.Factory.Create<T>(context.Receiver, (newValue) => context.OnChanged(newValue)));