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.
Related
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.
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.
Im having a bit of trouble with displaying a list in my listbox.
When I had everything in one class, things seemed to work fine but I cant figure out why it doesnt work now. My app, when clicked on the scan button, goes to a different class where there is a new thread created to scan for available bluetooth devices and the a list with those devices is created. Once the list is passed back to a method in Form1 class, it doesnt update the listbox. In debugging mode I could see that there are items on the list but nothing appears in the listbox. The listbox displays items if I did listBox1.Items.Add("Hello World") from the scan button click method. Im sort of stuck here. Ive just started learning C# and if anyone could help me that would be greatly appreciated.
public partial class Form1 : Form
{
int PanelWidth;
bool PanelCalShow;
public Form1()
{
InitializeComponent();
PanelWidth = PanelCal.Width;
PanelCalShow = false;
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (PanelCalShow)
{
PanelCal.Width = PanelCal.Width + 10;
if (PanelCal.Width >= PanelWidth)
{
timer1.Stop();
PanelCalShow = false;
this.Refresh();
}
}
else
{
if (PanelCalShow != true)
{
PanelCal.Width = PanelCal.Width - 10;
if (PanelCal.Width <= 0)
{
timer1.Stop();
PanelCalShow = true;
this.Refresh();
}
}
}
}
// Bluetooth connection
private void BtnScan_Click(object sender, EventArgs e)
{
var instance = new BtCom();
instance.Scan();
}
public void LbClientUpdate(List<string> DiscoveredDevices)
{
listBox1.DataSource = DiscoveredDevices;
}
}
and the bluetooth connection class
public class BtCom
{
public List<string> DiscoveredDevices = new List<string>();
Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB");
public void Scan()
{
Thread bluetoothScanThread = new Thread(new ThreadStart(Scanning));
bluetoothScanThread.Start();
}
BluetoothDeviceInfo[] devices;
public void Scanning()
{
var form1 = new Form1();
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
foreach (BluetoothDeviceInfo d in devices)
{
DiscoveredDevices.Add(d.DeviceName);
}
form1.LbClientUpdate(DiscoveredDevices);
}
}
The reason you aren't seeing any update on your original form is that you are creating a new instance of the Form1 class inside of your BtCom class instead of using the original instance.
One way you could fix this would be to pass the original instance of the form to your BtClass through a parameter to the Scan method, and then pass it along to your Scanning method. This way you will be calling methods on the same instance of the form that's running.
The problem with that is you will be blocking your UI while waiting for the thread to finish (assuming you call bluetoothScanThread.Join() to wait for the thread results).
A slightly different solution would be to use Tasks, with async methods that await results.
To do this, you would have your scan method return a Task<List<string>> (which is a Task that returns a List<string> representing the devices).
Then in form1 you would create an async method (called GetDatasource below) that creates an instance of your BtCom class, awaits the scan method, and returns the Task<List<string>>.
Finally, you would also make the Click method async and have it assign await the GetDatasource method and assign the Datasource when it returns.
By doing it this way, you isolate the BtCon class from having to know any details about the Form1 class, which is a good habit to get into because you end up creating more reusable and independent code.
Here's an example of all those words in code:
Make the scan method return a Task<List<string>> that can be used for the datasource (and have Scanning return a List<string>). Notice that the list is now private to the scanning method. It's a good practice to limit the scope of variables to only the level they are needed.:
public class BtCom
{
Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB");
public Task<List<string>> Scan()
{
var bluetoothScanTask = Task.Factory.StartNew(Scanning);
bluetoothScanTask.Wait();
return bluetoothScanTask;
}
private List<string> Scanning()
{
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
List<string> discoveredDevices = new List<string>();
foreach (BluetoothDeviceInfo d in devices)
{
discoveredDevices.Add(d.DeviceName);
}
return discoveredDevices;
}
}
Then, write an async method that will get the datasource by creating a new instance of this class, and await for the method to return. Also, make the Click method async so it can await the datasource method:
public partial class Form1 : Form
{
// Other form code omitted...
private async void BtnScan_Click(object sender, EventArgs e)
{
listBox1.DataSource = await Task.Run(GetDatasource);
}
private async Task<List<string>> GetDatasource()
{
var btCom = new BtCom();
List<string> results = await btCom.Scan();
return results;
}
Now your users can click the button and the form will continue to respond while the scanning takes place, and your listbox will populate when the scan method finishes.
For more on async and await, check your favorite search engine (like this page on Asynchronous programming, for example).
I have 2 Forms: V.Batch and V.BatchEdit and a Class: M.Batch
In V.Batch there is a DataGrid. I want to pass the value I get from the DataGrid to V.BatchEdit and the get set method is in M.Batch.
The problem here is that the value isn't passed properly in V.BatchEdit. It returns 0.
Here is the code
V.Batch:
M.Batch bt;
public Batch()
{
bt = new M.Batch();
InitializeComponent();
}
private void metroButton3_Click_1(object sender, EventArgs e)
{
bt.batchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
V.BatchEdit bEdit = new V.BatchEdit();
this.Hide();
bEdit.Show();
}
M.Batch:
public int batchNum;
public int BatchNum
{
set { batchNum = value; }
get { return batchNum; }
}
V.BatchEdit
static M.Batch bt = new M.Batch();
DataSet a = bt.getBatch(bt.batchNum);
public BatchEdit()
{
db = new Database();
InitializeComponent();
System.Windows.Forms.MessageBox.Show(bt.batchNum.ToString() + "Batchedit");
try
{
metroTextBox1.Text = a.Tables[0].Rows[0][2].ToString();
}
catch (Exception exceptionObj)
{
MessageBox.Show(exceptionObj.Message.ToString());
}
}
I'm new to coding and c#. I'm not sure if I placed static even though it should not be static or what.
Yes, you are using static improperly here.
The easiest way to see what's going wrong is to notice that you are calling new M.Batch() twice. That means you have two different instances of M.Batch in your application. And nowhere in your code do you attempt to share those instances.
What you should be doing is passing your instance of M.Batch from one form to another, e.g. in the constructor:
// V.Batch
bt.batchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
V.BatchEdit bEdit = new V.BatchEdit(bt);
this.Hide();
bEdit.Show();
// V.BatchEdit
private M.Batch bt;
private DataSet a;
public BatchEdit(M.Batch batch)
{
this.bt = batch;
this.a = this.bt.getBatch(bt.batchNum)
// Rest of your code here.
}
If You don't need the 'M.Batch' class for something else and you only use it for passing the value to V.BaychEdit, just declare a public property in V.BatchEdit like you did in M.Batch and use it like this:
V.BatchEdit bEdit = new V.BatchEdit();
bEdit.BatchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
Your problem is that although your using statics you're still assigning a new instance to the static field.
I am currently working with a WCF application. I must display the data received from callback in a DataGridView. These are my codes:
From FrmMain form:
private void button1_Click(object sender, EventArgs e)
{
InstanceContext callbackInstance = new InstanceContext(new StockExchangeUpdates());
SubscribingClient.RegisterSubscriberServiceClient proxy = new SubscribingClient.RegisterSubscriberServiceClient(callbackInstance);
proxy.RegisterSubscriber(Guid.NewGuid());
}
Class StockExchangeUpdates
[CallbackBehavior(UseSynchronizationContext = false)]
public class StockExchangeUpdates : IRegisterSubscriberServiceCallback
{
int ctr = 0;
FrmMain main = new FrmMain();
public void passGeneratedNumber(int num)
{
try
{
ctr = ctr + 1;
main.dgRandom.Rows.Add(DateTime.Now.ToString("h:mm:ss"), num, ctr);
// this is not working..
// Error: "dgRandoms" is inaccessible due to its protection level
}
catch (Exception)
{
throw;
}
}
}
I got use to try different ways but it is still not working. Please help! Thanks a lot!
I think you might need to set a different "Modifier" on your DataGridView.
That is, in the properties window for "dgRandom", change the property "Modifiers" to "Public" (or "Internal", if that is enough). If it is set to "Private", it will only be "seen" from within the same class.
(Edit: I assume you are using Windows forms and not WPF)