Loop for Getpoint in a WPF Modal form

Loop for Getpoint in a WPF Modal form

s_velasquez
Advocate Advocate
1,383 Views
10 Replies
Message 1 of 11

Loop for Getpoint in a WPF Modal form

s_velasquez
Advocate
Advocate

I need to create a loop for inserting blocks from a WPF MODAL form.
But I'm not getting it with my code using PromptPointOptions, I have a Flash of the form every time I enter a point.

How can I fix my code?

Thanks

 

// This is the code that displays the modal form
public class Commands
{
    [CommandMethod("ModalForm")]
    public static void ModalForm()
    {
        var dialog = new WpfModalForm();
        // carrega o formulario
        var result = AcAp.ShowModalWindow(AcAp.MainWindow.Handle, dialog, false);
    }
}

// This is the code for the button that asks you to select points

private void OkButtonName_Click(object sender, RoutedEventArgs e)
  {
      var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
      var ppo = new PromptPointOptions("\nSpecify insertion point: ");
      ppo.AllowNone = true; // allows a null value

      while (true)
      {
          var ppr = ed.GetPoint(ppo);
          if (ppr.Status == PromptStatus.OK)
          {
              ed.WriteMessage("\nInsert and process the block at the point: " + ppr.Value.ToString());
          }
          else 
          {
              ed.WriteMessage("\nNo points specified, the form will be reopened");
              break;
          }
      }
  }

 

0 Likes
Accepted solutions (3)
1,384 Views
10 Replies
Replies (10)
Message 2 of 11

norman.yuan
Mentor
Mentor
Accepted solution

When a modal form (dialog box) is shown, in order to hide the form for user to interact with the Editor (picking point, in your case) and then back to the modal form, you call Editor.StartUserInteraction(), which hide the form and then shows it back:

 

 

private void OkButtonName_Click(object sender, RoutedEventArgs e)
  {
      var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
      using (ed.StartUserInteraction(this))
      {
         var ppo = new PromptPointOptions("\nSpecify insertion point: ");
         ppo.AllowNone = true; // allows a null value
         while (true)
         {
           var ppr = ed.GetPoint(ppo);
           if (ppr.Status == PromptStatus.OK)
           {
              ed.WriteMessage("\nInsert and process the block at the point: " + ppr.Value.ToString());
           }
           else 
           {
              ed.WriteMessage("\nNo points specified, the form will be reopened");
              break;
           }
         }
      }
  }

 

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 11

_gile
Consultant
Consultant
Accepted solution

Hi,

You can try using Editor.StartUserInteraction method.

private void Button_Click(object sender, RoutedEventArgs e)
{
    var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
    var ppo = new PromptPointOptions("\nSpecify insertion point: ");
    ppo.AllowNone = true; // allows a null value

    using (ed.StartUserInteraction(this))
    {
        while (true)
        {
            var ppr = ed.GetPoint(ppo);
            if (ppr.Status == PromptStatus.OK)
            {
                ed.WriteMessage("\nInsert and process the block at the point: " + ppr.Value.ToString());
            }
            else
            {
                ed.WriteMessage("\nNo points specified, the form will be reopened");
                break;
            }
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 11

s_velasquez
Advocate
Advocate

Thanks to Norman and Gile for the response.
Using Editor.StartUserInteraction method solved my problem.

 

0 Likes
Message 5 of 11

s_velasquez
Advocate
Advocate

Does anyone know of a way to use 'using '(ed.StartUserInteraction(...)' or something similar in a class or static method?

0 Likes
Message 6 of 11

norman.yuan
Mentor
Mentor

I assume that you want to place the code of user interacting with Editor (e.g. calling Editor.GetXxxx() in a shared utility class as static methods and then call these static methods in the UI's code behind (yes, that is good practice of separating CAD dealing code with UI code).

 

You can wrap your static methods, which call Editor.GetXxx() inside, with overloaded method that accepts either IWin32Window (for Win Form UI), or System.Windows.Window (for WPF UI) as input. Something like:

public static Point3d? SelectPointInMdiDocument(Editor ed)
{
  var res=ed.GetPoint("\nSelect point:");
  if (res.Status==PromptStatus.OK)
  {
    return res.Value;
  }
  else
  {
	return null;
  }
}

public static Point3d? SelectPointInMidDocument(System.Windows.Window modalUi)
{
	var dwg=Application.DocumentManager.MdiActiveDocument;
	var ed=dwg.Editor;
	using (ed.StartUserInteraction(modalUi)
	{
		return SelectPointInMdiDocument(ed);
	}
}
public static Point3d? SelectPointInMidDocument(Form modalUi)
{
	var dwg=Application.DocumentManager.MdiActiveDocument;
	var ed=dwg.Editor;
	using (ed.StartUserInteraction(modalUi)
	{
		return SelectPointInMdiDocument(ed);
	}
}

 

Then, in your modal dialog's code behind, you can do:

private void Button_Click(...)
{
        // the form's code really does not need to know
        // when/how to hide the form and get user input from Editor
	var selectedPt=TheUtilityClass.SelectPointInMdiDocument(this);
	if (selectedPt.HasValue)
	{
		// Show the point coordinate on the modal UI
	}
}

 

HTH

 

Norman Yuan

Drive CAD With Code

EESignature

Message 7 of 11

s_velasquez
Advocate
Advocate

Thanks for the answer Norman,

See the tests I did in my project trabalhando com o AutoCAD 2025:

1 - 'SelectPointInMdiDocument' I changed the argument 'this' to 'ed' and it worked without problems.

2- the methods 'SelectPointInMidDocument(System.Windows.Window modalUi)' and 'SelectPointInMidDocument(Form modalUi)' showed the error below:

 

"Exception thrown: 'System.ArgumentException' in accoremgd.dll
An exception of type 'System.ArgumentException' occurred in accoremgd.dll but was not handled in user code
Window is not active:"
Please tell me where my mistake is

 

 private void OkButtonName_Click(object sender, RoutedEventArgs e)
 {
     var doc = AcAp.DocumentManager.MdiActiveDocument;
     var ed = doc.Editor;
 
     var modalUi = new WpfModalForm();

     var selectedPt = JigManager.TheUtilityClass.SelectPointInMidDocument(modalUi);
     NameBox.Text = selectedPt.ToString();
 }

 

 

 

0 Likes
Message 8 of 11

norman.yuan
Mentor
Mentor

What is this? Why do not need to create an instance of WPF window and pass it to SelectPointInMidDocument()?

 

var modalUi = new WpfModalForm();

 

 

I assume the "Ok" button that is clicked is on a modal UI (WPF, or Win Form), which should be the one being passed to SelectPointInMidDocument() method, that is:

 

var selectedPt = JigManager.TheUtilityClass.SelectPointInMidDocument(this);

 

 

By the way, the error you get is because you pass in a non-displayed, non-modal window to the StartUserInteraction()!

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 9 of 11

s_velasquez
Advocate
Advocate

Hi Norman,

You are right,

By the way, the error you get is because you pass in a non-displayed, non-modal window to the StartUserInteraction()!

That is my mistake.

I am calling your method in a static class so it does not work. I have 13 WPF windows in my project and I thought about using a single function to handle the insertion of blocks using.

The 'Block Insertion' class handles the insertion of blocks using 'Jig'

 

 

 

private void GetPointButton_Click(object sender, RoutedEventArgs e)
{
	// Calling a static class
    BlockInsertion.Insert("BlockTest");
}

//My static class
public static class BlockInsertion
{
    public static void Insert(string blockName)
    {
        var doc = AcAp.DocumentManager.MdiActiveDocument;
        var db = doc.Database;
        var ed = doc.Editor;
		
        // Collect insertion point here
        var selectedPt = JigManager.TheUtilityClass.SelectPointInMdiDocument(WpfModalForm);
        if (selectedPt.HasValue)
        {
            ed.WriteMessage("/nslectedPT: " + selectedPt.ToString());
        }
	// ...	
    }
}

 

 

 

0 Likes
Message 10 of 11

norman.yuan
Mentor
Mentor
Accepted solution
var selectedPt = JigManager.TheUtilityClass.SelectPointInMdiDocument(WpfModalForm);

 

What is WpfModalForm? Where is it declared and the modal form is instantiated and displayed? If it is indeed a modal form that is shown as modal form, how can your code reaches it in a static class/method without passing it in as a parameter? It looks to me, the code is not well structured even you managed to compile it.

 

Also, the JigManager used inside implies that AFTER selecting a point, the block would be inserted in the "Jig" style, which means the user would continue to interacting with the Editor. So, it does not make sense to only call Editor.StartUserInteraction() inside the SelectPointInMdiDocument() method - you should hide the modal form in the whole process of block insertion.

 

So, since you want the block insertion is done in a re-usable static method, meaning, it could be called from, or not from a modal UI. Obviously, when called from modal UI, you want to hide the UI first and show it back after. The simplest way is the same as I showed in previous reply: just add another OVERLOAD Insert() method that take either Win Form, or WPF Window as input:

 

private void GetPointButton_Click(object sender, RoutedEventArgs e)
{
	// Calling a static class
    BlockInsertion.Insert("BlockTest", this);
}

//My static class
public static class BlockInsertion
{
    public static void Insert(string blockName)
    {
        var doc = AcAp.DocumentManager.MdiActiveDocument;
        var db = doc.Database;
        var ed = doc.Editor;
		
        // Collect insertion point here
        var selectedPt = JigManager.TheUtilityClass.SelectPointInMdiDocument();
        if (selectedPt.HasValue)
        {
            ed.WriteMessage("/nslectedPT: " + selectedPt.ToString());
        }
		// ...	
    }
	
	public static void Insert(string blockName, System.Windows.Window modalWindow)
    {
        var doc = AcAp.DocumentManager.MdiActiveDocument;
        var db = doc.Database;
        var ed = doc.Editor;
		
        using (ed.StartUserInteraction(modalWindow)
		{
			Insert(blockName);
		}
    }
}

In this case, you want to relabel/rename the button on the form from "Point >" to "Insert >" and from "GetPointButton" to "InsertBlockButton", not because you have to, but for code's easy readability😅

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 11 of 11

s_velasquez
Advocate
Advocate

Thank you very much Norman, Your code worked perfectly, I have a lot to learn from it.

0 Likes