Revit API WinForms - Passing ComboBox value back to Command - c#

I'm trying to pass a value(an element id) from a WinForm back to the Command.cs file but I'm getting an error:
System.NullReferenceException: Object reference not set to an instance of an object.
at BatchSheetMaker.Command.Execute(ExternalCommandData commandData, String& message, ElementSet elements)
I'm following the youtube tutorial here and it seems fairly easy and straight forward but passing back to the Command.cs is another layer of complexity.
I have the Command.cs code wrapped in a try/catch block which just tells me that there's nullReferenceException however it doesn't tell me which line it's occurring at. I've looked around but havn't found any tips on how to make the debug show the error line. If anyone has any other pointers, that'd be helpful.
Form1.cs
public partial class Form1 : System.Windows.Forms.Form
{
private UIApplication uiapp;
private UIDocument uidoc;
private Autodesk.Revit.ApplicationServices.Application app;
private Document doc;
private string myVal;
public string MyVal
{
get { return myVal; }
set { myVal = value; }
}
public Form1(ExternalCommandData commandData)
{
InitializeComponent();
uiapp = commandData.Application;
uidoc = uiapp.ActiveUIDocument;
app = uiapp.Application;
doc = uidoc.Document;
}
public delegate void delPassData(System.Windows.Forms.ComboBox text);
private void Form1_Load(object sender, EventArgs e)
{
//Create a filter to get all the title block types.
FilteredElementCollector colTitleBlocks = new FilteredElementCollector(doc);
colTitleBlocks.OfCategory(BuiltInCategory.OST_TitleBlocks);
colTitleBlocks.WhereElementIsElementType();
foreach(Element x in colTitleBlocks)
{
comboBox1TitleBlockList.Items.Add(x.Name);
}
}
private void button1Continue_Click(object sender, EventArgs e)
{
MyVal = comboBox1TitleBlockList.Text;
}
Command.cs
Form1 form1 = new Form1(commandData);
String elementString = form1.MyVal.ToString();
Element eFromString = doc.GetElement(elementString);
ElementId titleBlockId = eFromString.Id;
ViewSheet sheet = ViewSheet.Create(doc, titleBlockId);

Run your entire add-in inside the Visual Studio debugger and step through your code line by line. That will show you exactly where the exception is thrown and enable you to easily identify what is causing the problem.

Changed my code to this and it started working:
form1.cs
public string MyVal;
//{
//get { return myVal; }
//set { myVal = value; }
//}
this link was helpful along with tutorials on youtube on how to pass values from form to form.

Related

Stack overflow error when trying to inicialize variable c#

Whenever i open the TradeForm menu, i get this error on the line that says Conditions con = new Conditions();
System.StackOverflowException
Here is the code that is relevant
public partial class TradeForm : Form
{
Conditions con = new Conditions();
public TradeForm()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
if(con.foo >= 1)
{
lst1.Text = "text";
res.Luxuries++;
button1.Hide();
}
}
}
and in another class named Properties
public class Conditions : TradeForm
{
public int foo = 0;
}
As Conditions inherits from TradeForm, each time you create a new Conditions, you are creating a new TradeForm.
Whenever you create a TradeForm you create a new Conditions object as per the line throwing the exception.
When you create a new Conditions, you go back to 1.
This loops infinitely, hence the StackOverflow exception.

Clipboard.GetDataObject() always returns null

I am struggling with using clipboard to copy / paste object, so I created a very simple example to demonstrate the issue.
What is very frustrating is that the same code was working earlier and stopped recently and I am unable to figure out what is wrong.
Basically, the problem is that dataObject.GetData() always returns null even if dataObject.GetDataPresent() returned true earlier.
I am running on .Net 4.5.
using System;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var a = new TestClass();
a.Name = "Test";
a.Index = 1;
a.Live = true;
IDataObject dataObj = new DataObject();
// Method 1 : Not working
//dataObj.SetData(a);
// Method 2 : also not working
DataFormats.Format format = DataFormats.GetFormat(a.GetType().FullName);
dataObj.SetData(format.Name, false, a);
Clipboard.SetDataObject(dataObj, false);
}
private void button2_Click(object sender, EventArgs e)
{
IDataObject dataObject = Clipboard.GetDataObject();
// Method 1 : Not working
//if (dataObject.GetDataPresent(typeof(TestClass)))
//{
// // Issue => retrievedObj is ALWAYS null
// var retrievedObj = dataObject.GetData(typeof(TestClass));
//}
// Method 2 : also not working
if (dataObject.GetDataPresent(typeof(TestClass).FullName))
{
// Issue => retrievedObj is ALWAYS null
var retrievedObj = dataObject.GetData(typeof(TestClass).FullName);
}
}
}
public class TestClass
{
public string Name;
public int Index;
public bool Live;
}
}
Any ideas please ?
I am answering my own question to share my experience.
To keep a long story short, in the original code I wanted to copy / paste an object that was referencing an type (XmlFont, a wrapper type I created to allow serialization of Font type) which was not explicitly marked with Serializable attribute. The funny part though, is that this object was successfully serialized to / from a file using XmlSerializer, so this part is still unclear for me. But marking the XmlFont type as Serializable instantly solved the problem.

ListView not adding a valid string

I'm making a console terminal using ListView for my custom server.
It writes any string that was given to it from the same class Main but refuses if its from another Misc.
Heres a gif of the following code in action
The first part of the gif is from myFunction(). As you can see, the messagebox shows that str in stringToConsole() contains a string("report 1" and "report 2") but it wouldnt add it.
Second part of the gif is from Execute_Click event. As you can see, again the messagebox shows that str in stringToConsole() contains a string(whatever i type) and it would add it
Following code is in Class Misc.
Following code's strings are not able to be added.
public static string myFunction()
{
Main myClass = new Main();
myClass.stringToConsole("report 1", "ConsoleList");
Thread.Sleep(2000); // emulate work
myClass.stringToConsole("report 2", "ConsoleList");
return "string";
}
Following codes are inside the form class Main.
private void startupProcedure()
{
label1.Text = Misc.myFunction();
}
This add strings to the ListView(Console List)
public void stringToConsole(string str, string destination)
{
if (destination == "ConsoleList")
{
// to check if str has a value
MessageBox.Show(str); // string does have a value
ConsoleList.Items.Add(str); // refuse to use str from myFunction()
}
}
Following code's strings are able to be added.
private void Execute_Click(object sender, EventArgs e)
{
executeCommandLine(CommandLine.Text, "ConsoleList");
CommandLine.Clear();
}
public void executeCommandLine(string commandLine, string destination)
{
stringToConsole(commandLine, destination); // this shows in Listview
}
A very similar question was asked some hours ago. You have a very, very basic problem:
Main myClass = new Main();
You are instantiating a new Main form, however, you are never showing it or using it outside the function's scope, hence, you are not modifying the Main instance you want to modify.
An easy way to do this would be to pass the Main instance to the function:
public static string myFunction(Main formInstance)
{
formInstance.stringToConsole("report 1", "ConsoleList");
Thread.Sleep(2000); // emulate work
formInstance.stringToConsole("report 2", "ConsoleList");
return "string";
}
private void startupProcedure()
{
label1.Text = Misc.myFunction(this);
}

Visio Interop Application events causing undesired behaviour

I'm trying to use Visio Application events. When instantiating a new Application object, and setting any event (i.e. BeforeDocumentClose), this appears to result in unable to restore the Visio window after minimizing it.
I'm using VS/C# 2013, Windows Forms, Visio 2013 (on Windows 7). Though my main code project is huge implementing exchange between various office applications using Add-Ins, the following simple code reproduces the same issue. It is a Windows Forms project (with added Reference to Microsoft.Office.Interop.Visio).
using Visio = Microsoft.Office.Interop.Visio;
Visio.Application app;
bool initialised = false;
private void visioButton_Click(object sender, EventArgs e)
{
init();
app.Documents.Add("c:\\test.vst"); // creates new document from template
}
void init()
{
if (!initialised)
{
// only initialise once
app = new Visio.Application();
app.BeforeDocumentClose += app_BeforeDocumentClose;
initialised = true;
}
}
void app_BeforeDocumentClose(Visio.Document doc)
{
}
Issue #1: This is the main issue. Creating one or more Visio Documents, the Visio Window is not maximized after being minimized. No Exceptions thrown as far as I can see. Windows just does it's audible error 'ping'.
Issue #2: This is a secondary issue. Creating two or more Visio Documents, hovering over the Windows Taskbar, the preview windows show the waiting cursor instead of normal document preview.
Conditions: Issue #1 only occurs when using an event on the Application. Document, Page/Shape events don't cause any problem. All events are captured fine. Issue #2 always occurs, but this is less important for me.
I've been searching for this issue for a while, but can't find anything related to it, so any help is greatly appreciated.
I am not quite sure what is causing Visio to not respond to restore, but you can try the approach with "AddAdvise" instead:
[ComVisible(true)]
public partial class Form1 : Form, Visio.IVisEventProc
{
public Form1()
{
InitializeComponent();
}
Visio.Application app;
bool initialised = false;
private void button1_Click(object sender, EventArgs e)
{
init();
app.Documents.Add("C:\\test.vst"); // creates new document from template
}
void init()
{
if (!initialised)
{
// only initialise once
app = new Visio.Application();
// app.BeforeDocumentClose += app_BeforeDocumentClose;
app.EventList.AddAdvise(DocCloseEventCode, this, null, null);
initialised = true;
Application.DoEvents();
}
}
const short DocCloseEventCode = unchecked((short)Visio.VisEventCodes.visEvtDoc + (short)Visio.VisEventCodes.visEvtDel);
object Visio.IVisEventProc.VisEventProc(short eventCode, object source, int eventID, int eventSeqNum, object subject,object moreInfo)
{
if (eventCode == DocCloseEventCode)
app_BeforeDocumentClose(subject as Visio.Document);
return null;
}
void app_BeforeDocumentClose(Visio.Document doc)
{
}
}
To provide the completed solution for multiple events using Nikolay's advice, here is the completed code including both events and (de)initialisation of Visio Application, and without using templates. (Note that the Message boxes may turn up in the background, behind the Visio window.)
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Visio = Microsoft.Office.Interop.Visio;
namespace VisioInteropTest
{
[ComVisible(true)]
public partial class TestForm : Form, Visio.IVisEventProc
{
Visio.Application app;
bool initialised = false;
// all AddAdvise events:
// https://msdn.microsoft.com/en-us/library/office/ff768620.aspx
const short appCloseEventCode = (short)(Visio.VisEventCodes.visEvtApp | Visio.VisEventCodes.visEvtBeforeQuit);
const short docCloseEventCode = (short)(Visio.VisEventCodes.visEvtDoc | Visio.VisEventCodes.visEvtDel);
public TestForm()
{
InitializeComponent();
}
private void visioButton_Click(object sender, EventArgs e)
{
if (init())
{
app.Documents.Add("");
}
}
bool init()
{
if (!initialised)
{
app = new Visio.Application();
app.EventList.AddAdvise(appCloseEventCode, this, null, null);
app.EventList.AddAdvise(docCloseEventCode, this, null, null);
initialised = true;
}
return initialised;
}
object Visio.IVisEventProc.VisEventProc(short eventCode, object source, int eventID, int eventSeqNum, object subject, object moreInfo)
{
switch (eventCode)
{
case appCloseEventCode: app_BeforeAppClose((Visio.Application)subject); break;
case docCloseEventCode: app_BeforeDocumentClose((Visio.Document)subject); break;
}
return null;
}
void app_BeforeAppClose(Visio.Application app)
{
initialised = false;
MessageBox.Show("App closed");
}
void app_BeforeDocumentClose(Visio.Document doc)
{
MessageBox.Show("Doc closed");
}
}
}

How to populate a lstbox from a ,txt file at startup

I need to populate a listbox from a text file at startup. I also need to have the firt 2 lines eliminated from the listbox along with all blank lines, but that isn't to important right now. I am currently stuck at getting the listbox populated at all. Here is my code so far:
struct CDCLocationEntry
{
public string name;
}
public partial class StartupForm : Form
{
private List<CDCLocationEntry> CDCList = new List<CDCLocationEntry>();
public StartupForm()
{
InitializeComponent();
}
private void ReadFile()
{
try
{
StreamReader inputFile;
string line;
CDCLocationEntry entry = new CDCLocationEntry();
inputFile = File.OpenText("P3S1 Data File For Import.txt");
while (!inputFile.EndOfStream)
{
line = inputFile.ReadLine();
CDCList.Add(entry);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void DisplayText()
{
foreach (CDCLocationEntry entry in CDCList)
{
CDCLocationListBox.Items.Add(entry.name);
}
}
private void StartupForm_Load(object sender, EventArgs e)
{
ReadFile();
DisplayText();
}
visual studio is say my problem is here:
struct CDCLocationEntry
{
public string name;
}
the message I'm getting is:
Warning 1 Field 'Project_3___Section_1.CDCLocationEntry.name' is never
assigned to, and will always have its default value null
none of my notes or online help is giving me an answer for this.
Any help that you can provide would be greatly appreciated
You need to create a CDCLocationEntry instance inside the loop and assign, at this instance property name, the line coming from your file
inputFile = File.OpenText("P3S1 Data File For Import.txt");
while (!inputFile.EndOfStream)
{
CDCLocationEntry entry = new CDCLocationEntry();
entry.name = inputFile.ReadLine();
CDCList.Add(entry);
}
Your actual code creates just one instance of CDCLocationEntry outside the loop and, without assigning anything to the name property, adds this same instance in every loop.

Categories