EventCallback vs Action not working in blazor - c#

I'm trying to build a Proof of Concept with nested components.
I have a main-component which is declared the following
public abstract class VoidHtmlComponent : ComponentBase
{
[Parameter] public EventCallback<MouseEventArgs> OnClick { get; set; }
}
and I pass an instance of e.g a TableHead to my Table component
<Shared.RazorComponents.Table TableHead="#(new TableHead{ OnClick = HandleTableHeadClick})" >
</Shared.RazorComponents.Table>
#code{
private void HandleTableHeadClick(MouseEventArgs mouseEventArgs)
{
Trace.WriteLine($"TableHead has been clicked ...");
}
}
This will not build stating
Client\Pages\Table.razor(6,213): Error CS0428: Cannot convert method group 'HandleTableHeadClick' to non-delegate type 'EventCallback'. Did you intend to invoke the method?
I guess blazor is doing some magic here to convert the Action<MouseEventArgs> to an EventCallback<MouseEventArgs> but I am stuck at this point. I also changed the parameter to Action<MouseEventArgs> which throws an error on runtime saying the cast is invalid.
Already tried using EventCallbackFactory but got stuck there as well.
Using OnClick = new EventCallbackFactory().Create(this, HandleTableHeadClick) throws
Function statements require a function name
at runtime.

I think the issue is that you create an instance of the TableHead just like a property.
Since we don't know anything about the Table component it self I just assume that the issue is is around there.
The markup for using Renderfragments for this case would like like something like this:
<Shared.RazorComponents.Table>
<TableHead Context="context">
<p>put what ever you want to render here. Like the nested component with event handler</p>
</TableHead>
</Shared.RazorComponents.Table>
See the docs as a reference.

Related

Dynamic LINQ with Skip and Take causes Exception: Unknown LINQ expression of type 'Dynamic'

I'm building a report builder/runner using System.Linq.Dynamic.Core (1.2.20) in an ASP.NET MVC (5.2.9) app and I mostly have it working, except for one annoying issue. I can't get Skip and Take to work. Basically my code is doing this:
_context.SetDynamic("ENTITY_NAME")
.Where(_parsingConfig, WHERE_EXPRESSION)
.OrderBy(_parsingConfig, ORDER_BY_EXPRESSION)
.Skip(???)// exception
.Take(???)// exception
.Select(_parsingConfig, SELECT_EXPRESSION)
.ToDynamicListAsync();
Running that causes this exception:
Unknown LINQ expression of type 'Dynamic'.
When I remove Skip and Take then it works correctly and I see the results, but I lose out on the paging capabilities.
From what I can tell, it has to do with me starting out with SetDynamic which returns an IQueryable<object>. Elsewhere in the app I do the same query, but start out from a Set<T> and there's no problems with it.
What should I do to get Skip and Take to work?
After some more trial and error I got it to work. I manually tested switching to Set(Type) to see if it fixed Skip and Take and it did.
From there I decided to change the model for Report to contain a string Object property. It already had an ObjectType property which was an enum, but I decided to replace it with a string, and I'll probably do that everywhere else I use it and just remove it.
After that, using reflection I got all objects in the DbContext assembly that implement a marker interface called IEntity and projected them into an IList<Entity>:
public sealed class Entity {
public string DisplayName { get; set; }
public string Name { get; set; }
public Type Type { get; set; }
}
... and then stored them as a singleton for dependency injection. In the report runner class since I already know the report Id I just pull it out of the database and then pull out the Entity where Report.Object == Entity.Name from the list and pass the type off to Set(Type).
Kind of long winded, but it works. I had been planning to have something like that list for a little while so I can present it as drop down list when a new report is being created so the report runner knows where to start from when building the query.

Blazor bind data to collection?

I'm trying to generate forms with Blazor programmatically, and I'm running into an issue where I need to bind an InputText value to a member of a collection such as:
#foreach (var prop in formProperties)
{
<InputText id=#prop.Name #bind-Value="form.Responses[prop.Name]" />
}
However, I get the following exception:
System.ArgumentException: The provided expression contains a InstanceMethodCallExpression1 which is not supported. FieldIdentifier only supports simple member accessors (fields, properties) of an object.
Is it possible to bind the input to a collection of some sort?
Running into a similar issue where I'm trying to build a table based on a dictionary of attributes, I came across this reply from Steve.
Basically what you can do is introduce a new type called e.g.
public class FormResponse
{
public string Value { get; set;
}
Assuming you now create a dictionary of FormResponse on your form object, you can then do this:
#foreach (var prop in formProperties)
{
<InputText id="#prop.Name" #bind-Value="form.Responses[prop.Name].Value" />
}
Which is arguably more straightforward than creating a new component with Chained Binding.
Unfortunately, you cannot use the <InputText/> component for more complex accessors presently.
However, if you don't mind handling your own validation/notification code, you can roll your own by:
Changing the <InputText/> to an <input/>
Use #bind instead of #bind-Value
Using your code:
#foreach (var prop in formProperties)
{
<input id=#prop.Name #bind="form.Responses[prop.Name]" />
}
Again, you will loose change notifications, and validation, and all connection to the EditForm and EditContext.
You can also go the route that #dennis1679 suggested, creating a sub component. I am curious what the Chained Binding integration with the top level form/model validation would be like in practice with. I haven't played with that yet.
FYI, I did a quick search, and didn't see the issue (likely a feature) in github, but when I find it, I will update this.

SDK expecting to be assigned a Frame value C#

I am using the Particle Setup SDK, where I call a method which requires me to assign a value to
public Frame AppFrame { get; set; }
However, I am unsure what value I am supposed to assign it.
AppFrame = //What value am I meant to assign to it, a window.xaml,
//that contains a method of type Frame?
I tried to assign it a Window with a method called public Frame particleframe() although it is giving me the error Cannot implicitly convert type 'System.Windows.Controls.Frame' to 'Windows.UI.Xaml.Controls.Frame'. So I tried to directly assign it the correct library:
public Windows.UI.Xaml.Controls.Frame particleframe()
Unfortunately this didn't work as type UI doesn''t exist. Can anyone point me in the right direction?

Custom c# code in a Report

I am populating a report using an Object. Everything works fine, if my members are string, however, I have a few members, which are List<string>.
When I add these fields to the report (in designer, visual studio 2012) and run the report, they show as
'#Error'
Viewing the properties of the report, I can see that there is a 'custom code' tab, for which I've entered the following method to convert the list of strings into a array of string.
public string[] GetListItems(List<string> intList)
{
var s = intList.ToArray();
return s;
}
Then when I try and replace the field with an expression and enter the following:
=Join(Code.GetListItems(Fields!Aka.Value),",")
and then run the report, VS fails to build with the following:
Error 2 The Value expression for the textrun ‘Aka.Paragraphs[0].TextRuns[0]’ contains an error: [BC30456] 'GetListItems' is not a member of 'ReportExprHostImpl.CustomCodeProxy'.
Error 1 There is an error on line 0 of custom code: [BC30183] Keyword is not valid as an identifier.
Can anyone shed any light why this is?
That is C# code. Directly in the report you can only use Visual Basic. C# is avaliable as an external DLL.
For those who can't create go through the difficulties of implementing a third-party DLL. A simpler; but, a messier solution is as follows.
To summarize solution, you can create properties that returns a value that the reports can easily work with.
In my scenario, I had 2 classes:
public class Parent {
public Child { get; set; }
}
public class Child {
public string Name { get; set; }
}
The type that I was binding to my Report was Parent; however, I needed to access the Name property inside Child. In otherwords I needed to do:
Parent.Child.Name
This where I ran into the same problem that the OP ran into. Due to the scope of my project (a college project), I can't bother with third-party dlls or writing my own dll...
So what I did is add more properties to the Parent class.
public class Parent {
public Child { get; set; }
public string ChildName { get => Child.Name; }
}
public class Child {
public string Name { get; set; }
}
By adding an additional property to Parent that has an type that Reports can work with, I can now easily access the Child's Name through my Parentclass.
Of course this is messy; but, I'm in a situation where I can't go with the more complicated/time consuming dlls solution.
I just hope my instructors will allow this solution without penalty...
If you just created a report and showing an error code like
BC30016 labels are not valid outside of the method.
The reson in my case was that i have insert the random numerical value n the code property of a report1.rdlc
Hence to solve this type of error, goto report properties and remove the value from the code.

C# Generics, what am I doing wrong?

I'm some what new to Generics and I can't figure out why the following doesn't work.
I have an extension to IEnumerable<T>, called Grid and it looks like so
public static class IEnumberableGridExtension
{
public static HelperResult Grid<T>(this IEnumerable<T> gridItems, Action<GridView<T>> thegrid)
{
........
}
}
Say, I have a variable in my razor Model called "Products" and it is the type List<Product>, so I tried to do
#Model.Products.Grid<Product>(grid=>{
...
});
It states "Cannot convert method group 'Grid" to non-delegate type 'object'. Did you intend to invoke the method?", with "#Model.tasks.Grid" red underlined.
The funny thing is, visual studio compiles, everything is fine. Of course, if i simply do
#Model.Products.Grid(grid=>{
...
});
It's all fine.
The Razor parser is interpreting < and > as normal HTML tags.
You can avoid the problem wrapping the call in parenthesis:
#(Model.Products.Grid<Product>(grid=>{
...
}))
You can find additional info here: How to use generic syntax inside a Razor view file?

Categories