Disallow linking under certain circumstances

Hello,

I have following Problem to solve. I have a node which has two ports, one of the left and one on the right side. Now, when my model is in read-only mode, only links from These two specific ports are allowed.

In the linking tool, there is a method FindLinkablePort() which I can use. But it doesn’t exist for the Re-linking tool. And I don’t see how I can find out about the starting port there.

I Tried to Workaround by putting my code in the DoActivate method which can provide me with the necessary Information. There, when I want to disallow the links, I call base.DoCancel() and base.DoStop. But I experience a problematic behaviour there, namely that the Cursor (Hand Cursor) which becomes active when the user starts to drag the link, stays active after the cancel and stop method.

So am I doing sth. wrong with the cancellation of the started linking tool Action? Or even better, is there some way to Access the port Information I Need in the CanStart method?

Any help is appreciated.

Marc

When a diagram is “read-only”, no drawing of new links should be allowed. But perhaps you are in a slightly different situation. But I cannot tell what your situation is.

The RelinkingTool is only started when the user starts dragging a relinking handle on an existing Link.

FindLinkablePort is a method defined only on the LinkingTool, which is only started when the user starts dragging from an eligible port element in order to draw a new Link.

Maybe you want to override one of the IsValidFrom, IsValidTo, or IsValidLink methods?

Hi Walter,

thanks for your Input. There is a state of our workflow that is already active and in which the user must not do structural changes like adding a new node or a “normal” workflow Transition. But what he may do is adding time constraints between nodes which are expressed in our model by so called “timemonitoring” links.

Just tried to implement the requirement overwriting the isValidFrom/To methods. But the behaviour is different from my idea of disallowing the links upon doStart or DoActivate. With your proposal, the user can start the linking/re-linking operation (the according node is highlighted) but doesn’t find a valid target/source node where the link could start/end.

But meanwhile, I managed to implement a version that seems to what I wanted. In the DoActivate method, I now call base.DoCancel, base.DoDeactivate and base.DoStop all together and it seems to cleanup everything now. So I think I will stick to this approach.

Thanks,
Marc

Just calling DoCancel() should be sufficient to stop the tool and rollback any changes. DoCancel should call StopTool, which will call DoDeactivate (if it was Active) and then DoStop.

If you had overridden IsValidFrom and IsValidTo, or IsValidLink, to return false, the LinkingTool will not run.

Hi Walter,

just did some experiments after reading your last comments.

  1. I implemented my logic for the read-only case in IsValidLink. But the result is that the user can start the linking operation but doesn’t find a valid to/from node.
  2. For me, calling DoCancel is not sufficient. If I just call this method, there is some strange behaviour. The start and end node stay highlighted (Magenta border) and the link itself gets a wrong link template (latter is a Problem by me I guess).

Maybe this has to do with the fact that in my DoActivate implementation I call the base impl. before my logic and the DoCancel? But I have to call the base impl. first in order to have the Information about the original from port available.

Kind regards,
Marc

public override void DoActivate()
{
	if (this.Model.IsReadOnly)
	{
		this.DoCancel();
	}

	base.DoActivate();

	var fromPort = this.OriginalFromPort;

	if (this.Model.IsActiveVersion && fromPort != null)
	{
		var portId = fromPort.GetValue(Node.PortIdProperty) as string;
		if (portId != STOPortIds.PortLeft.ToString() && portId != STOPortIds.PortRight.ToString())
		{
			base.DoCancel();
//                    base.DoDeactivate();
//                    base.DoStop();
			return;
		}
	}
	...
}

It seems wrong to call DoCancel and then go ahead and call DoActivate anyway.

Fundamentally you want to cause CanStart() to return false. Overriding DoActivate is too late.

The easiest way to affect CanStart in your case might be to override GoXam for WPF 2.2.4. Call the base method and return null if that port element does not meet your requirements.

Hi Walter,

your first Statement is absolutely correct. The code is missing a return there after DoCancel. My fault.

The Problem with FindLinkablePort is that it doesn’t exist in the RelinkingTool as I stated in my first comment in this thread. And I didn’t find out a way to gather the relevant Information about the originating port there. That was the reason why I started playing around with the DoActivate in the first place.

After you mentioned relinking, you talked about adding new links, so I didn’t know which tool you were talking about.

Nevertheless, what I just said about overriding CanStart is basically right.

Here’s the implementation of RelinkingTool.CanStart:

    public override bool CanStart() {
      if (!base.CanStart()) return false;

      Diagram diagram = this.Diagram;
      if (diagram == null || diagram.IsReadOnly) return false;
      if (!diagram.AllowRelink) return false;
      IDiagramModel model = diagram.Model;
      if (model == null || !model.Modifiable) return false;
      if (!IsLeftButtonDown()) return false;
      FrameworkElement h = FindToolHandleAt(diagram.FirstMousePointInModel, "RelinkFrom");
      if (h == null) h = FindToolHandleAt(diagram.FirstMousePointInModel, "RelinkTo");
      return h != null;
    }