Blazor.Diagrams icon indicating copy to clipboard operation
Blazor.Diagrams copied to clipboard

Replacing DragNewBehavior causes RenderLinkTree NullReferenceError

Open tarp-jusf opened this issue 1 year ago • 5 comments

I have tried making a custom DragNewBehavior, because I only want to be able to drag links from outgoing Ports. This results in the RenderLinkTree call to experience a NullReferenceError.

I have tried copying the DragNewBehavior code to check if it was my code, but it also breaks. I traced some code while debugging and copied the tracelog up until the error.

dbug: Microsoft.AspNetCore.Components.RenderTree.Renderer[3]
      Rendering component 82 of type Blazor.Diagrams.Components.Renderers.PortRenderer
dbug: Microsoft.AspNetCore.Components.RenderTree.Renderer[3]
      Rendering component 59 of type Blazor.Diagrams.Components.DiagramCanvas
dbug: Microsoft.AspNetCore.Components.RenderTree.Renderer[1]
      Initializing component 90 (Blazor.Diagrams.Components.Renderers.LinkRenderer) as child of 59 (Blazor.Diagrams.Components.DiagramCanvas)
dbug: Microsoft.AspNetCore.Components.RenderTree.Renderer[3]
      Rendering component 90 of type Blazor.Diagrams.Components.Renderers.LinkRenderer
dbug: Microsoft.AspNetCore.Components.RenderTree.Renderer[1]
      Initializing component 91 (Blazor.Diagrams.Components.LinkWidget) as child of 90 (Blazor.Diagrams.Components.Renderers.LinkRenderer)
dbug: Microsoft.AspNetCore.Components.RenderTree.Renderer[3]
      Rendering component 91 of type Blazor.Diagrams.Components.LinkWidget
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
   at Blazor.Diagrams.Components.LinkWidget.BuildRenderTree(RenderTreeBuilder __builder)
   at Microsoft.AspNetCore.Components.ComponentBase.<.ctor>b__6_0(RenderTreeBuilder builder)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)

tarp-jusf avatar Nov 30 '23 14:11 tarp-jusf

After looking into this, it seems that DragNewLinkBehavior is being used multiple places. So replacing this behavior will make the whole thing break. image

A solution could be to change the RegisterBehavior function replace the class associtated with a certain type of behavior.

That way when you use e.g GetBehavior<DragNewLinkBehavior>, you could get a return of type CustomDragNewLinkBehavior, which can be checked in a if-statement. image

tarp-jusf avatar Dec 04 '23 08:12 tarp-jusf

After even more investigation, the LinkWidget, which uses DragNewLinkBehavior, is used by the LinkRenderer. The LinkRenderer is not replaceable, unlike other controls that are.

I think there's some architecture design that's gone awry, and trying to change things to fit, becomes a cascade of changes.

There might be some ground-up work that needs to be rethought.

tarp-jusf avatar Dec 04 '23 14:12 tarp-jusf

Hello, thank you for opening this issue.

First of all, regarding your specific need, wouldn't using the Options.Links.Factory (https://github.com/Blazor-Diagrams/Blazor.Diagrams/blob/master/src/Blazor.Diagrams.Core/Options/DiagramLinkOptions.cs#L30) option solve your issue? If the factory returns null (instead of a link instance), then nothing happens. You can simply check whether it's an outgoing port and response accordingly.

Secondly, you are right. The fact that other components use behaviors directly is an issue since that would stop users from essentially replacing said behavior, and that's not what I want the library to do, since I emphasize heavily on customizability.

I was thinking for a while about creating interfaces or abstract classes for the base behaviors, so that:

  1. Other parts of the library use that instead of the implementation directly
  2. Give users some default or helpful methods so that they don't really have to copy/paste the whole class from the library and change what they want

I'll probably start working on that soon, let me know what you think!

zHaytam avatar Dec 04 '23 15:12 zHaytam

I'm using an external service to create connections. It would be interesting to customize existing behavior.

SergeyIlyin avatar Jan 08 '24 17:01 SergeyIlyin

@zHaytam thanks for this great library.

I have created some derived behaviors and, to not break so much your implementation I changed the GetBehavior function and, if the asked one not found, check if has a derived one.

vbalestone avatar Apr 23 '24 20:04 vbalestone