I am trying to set the location of the control after some event based on the location of EventArg pictureBox1.Location.X = e.X;.
However this does not work it Cannot Modify expression because it is not a variable. But i was under the impression that x coordinate is a property and can be set. What is going on here ?
Because System.Drawing.Point is a value type, when you call pictureBox1.Location, you are actually getting a copy of the Point. A whole new object is constructed and filled with the fields of pictureBox1.Location.
As such, the compiler is trying to protect you from doing something silly, as changing the value of the copy would not propagate to the value of Location.
As such, and as mentioned in the other answers, you should construct a new Point and assign it to the Location property.
Try this instead:
pictureBox1.Location = new Point(e.X, pictureBox.Location.Y);
or if you don't want to construct a new variable:
Point location = pictureBox1.Location;
location.X = e.X;
pictureBox1.Location = location;
This is because Point is a value type, and therefore you can't just edit one of its values, as it won't propagate. Its value is stored, not a reference to the value. You can't just edit it, you need to build the object again. This could compile, but it would do absolutely nothing, in no possible scenario, so the compiler makes sure you don't do this error.
Some people here talk about Point is a value type and you can't change its X and Y, that kind of explanation can confuse you much. I post this answer here to help you understand why you can't change it's Location. That's because Location is a Property which returns a Structure not a reference to an Object, if you have a field instead, you can change that way, like this:
public class YourControl : BaseControl {
public Point Location;
}
//Then you can change the Location your way:
yourControl.Location.X = ....
However, as I said, Location is a Property which returns a copy of a value type (structure), like this:
public class YourControl : BaseControl {
private Point location;
public Point Location {
get {
return location;//a copy
}
set {
location = value;
}
}
}
//So when you call this:
yourControl.Location
//you will get a copy of your Location, and any changes made on this copy won't affect
//the actual structure, the compiler needs to prevent doing so.
yourControl.Location.X = ... //Should not be executed...
This is not the only case for Location, you can find this issue in all other Properties which are value types.
Related
I feel like I'm missing something complete obvious so I apologise in advance if (when?) that is the case.
I'm trying to do something really simple, change a bool value in a struct from false to true. Obviously I can't change it directly, so I created a method within the struct that I can call which should change the value there. It doesn't seem to be the case. Here is the code and I'd appreciate any insight;
public Dictionary<int, List<ScanLineNode>> allScanLineNodes = new Dictionary<int, List<ScanLineNode>>();
public void MethodName(ScanLineNode node [...])
{
//This will perform a raycast from the Node's position in the specified direction. If the raycast hits nothing, it will return Vector3.zero ('Row is complete'), otherwise will return the hit point
Vector3 terminationPoint = node.RaycastDirection(node, direction, maxDist, targetRaycast, replacementColour, backgroundColour);
ScanLineNode terminationNode = new ScanLineNode();
//Previously attempted to store a local reference to this row being used, but also did not work
//List<ScanLineNode> rowNodes = allScanLineNodes[node.rowNumber];
[...]
if (terminationPoint == Vector3.zero)
{
//Definitely reaches this point, and executes this function along the row, I have added breakpoints and checked what happens in this for loop. After running 'RowComplete' (which just changes 'rowComplete' from false to true) 'rowComplete' is still false. Just in case I've included the RowComplete() function below.
Debug.Log("Row Complete: " + node.rowNumber);
for (int i = 0; i < allScanLineNodes[node.rowNumber].Count; i++)
{
allScanLineNodes[node.rowNumber][i].RowCompleted();
}
}
}
ScanLineNode Struct -- Most stuff is hidden (that I don't believe is affecting this), I have included the RowComplete() function however.
public struct ScanLineNode
{
[...]
public bool rowComplete;
[...]
public ScanLineNode([...])
{
[...]
rowComplete = false;
[...]
}
public void RowCompleted()
{
rowComplete = true;
}
}
I have also confirmed that RowCOmpleted() does not get called anywhere aside the above location, and 'rowComplete' is only called from the RowComplete() function
(from comments) allScanLineNodes is a Dictionary<int, List<ScanLineNode>>
Right; the indexer for a List<ScanLineNode> returns a copy of the struct. So when you call the method - you are calling it on a disconnected value on the stack that evaporates a moment later (is overwritten on the stack - this isn't the garbage collector).
This is a common error with mutable structs. Your best bet is probably: don't make mutable structs. But... you could copy it out, mutate it, and then push the mutated value back in:
var list = allScanLineNodes[node.rowNumber];
var val = list[i];
val.RowCompleted();
list[i] = val; // push value back in
But immutable is usually more reliable.
Note: you can get away with this with arrays, since the indexer from an array provides access to a reference to the in-place struct - rather than a copy of the value. But: this isn't a recommendation, as relying on this subtle difference can cause confusion and bugs.
I've tried the following code:
this.balancePanel.Location.X = this.optionsPanel.Location.X;
to change the location of a panel that I made in design mode while the program is running but it returns an error:
Cannot modify the return value of 'System.Windows.Forms.Control.Location' because it is not a variable.
So how can I do it?
The Location property has type Point which is a struct.
Instead of trying to modify the existing Point, try assigning a new Point object:
this.balancePanel.Location = new Point(
this.optionsPanel.Location.X,
this.balancePanel.Location.Y
);
Location is a struct. If there aren't any convenience members, you'll need to reassign the entire Location:
this.balancePanel.Location = new Point(
this.optionsPanel.Location.X,
this.balancePanel.Location.Y);
Most structs are also immutable, but in the rare (and confusing) case that it is mutable, you can also copy-out, edit, copy-in;
var loc = this.balancePanel.Location;
loc.X = this.optionsPanel.Location.X;
this.balancePanel.Location = loc;
Although I don't recommend the above, since structs should ideally be immutable.
Use either:
balancePanel.Left = optionsPanel.Location.X;
or
balancePanel.Location = new Point(optionsPanel.Location.X, balancePanel.Location.Y);
See the documentation of Location:
Because the Point class is a value type (Structure in Visual Basic,
struct in Visual C#), it is returned by value, meaning accessing the
property returns a copy of the upper-left point of the control. So,
adjusting the X or Y properties of the Point returned from this
property will not affect the Left, Right, Top, or Bottom property
values of the control. To adjust these properties set each property
value individually, or set the Location property with a new Point.
If somehow balancePanel won't work, you could use this:
this.Location = new Point(127, 283);
or
anotherObject.Location = new Point(127, 283);
You need to pass the whole point to location
var point = new Point(50, 100);
this.balancePanel.Location = point;
When the parent panel has locked property set to true, we could not change the location property and the location property will act like read only by that time.
Say I have my class, and I have the non-static variable
int x = 5;
After the code runs x is changed to something else, how can I get the value x started with using reflection?
Short answer: you can't.
If you implement some kind of custom transactional system, than it is possible. Out of the box: no luck.
And yes, the custom transactional system can be very simple: add another field or property that you use to 'remember' the initial value.
if i understand you correctly you want the initial value of the x.
for that you need another member or parameter to keep the first initializing of x. for example in your class:
int FirstX = -1;// or any other value you know ain't gonna come
bool firstInitial = true;
public int X
{
set
{
if(firstInitial)
{
FirstX = value;
firstInitial = false;
}
x = value
}
}
Now if you mean default value that is set at class level, you already know as it is constant other way would be creating an instance of the class for which you need default value.
ClassName className= new ClassName();
className.MyProp//This will always give default value.
new ClassName().MyProp //would also do.
If you want list of transactional values you need to implement it, reflection is not meant for that.
I get the following error in my code and I'm not sure why:
Warning - 'SummaryForm.m_difficulty' is never assigned to, and will always have its default value 0
Code
public partial class SummaryForm : Form
{
// Declares variables with the values pulled from the 'MainForm'
int iCorrectACount = MainForm.iCorrectACount;
int iCurrentQIndex = MainForm.iCurrentQIndex;
private Difficulty m_difficulty;
public SummaryForm()
{
InitializeComponent();
double modifier = 1.0;
if (m_difficulty == Difficulty.Easy) { modifier = 1.0; }
if (m_difficulty == Difficulty.Medium) { modifier = 1.5; }
if (m_difficulty == Difficulty.Hard) { modifier = 2; }
// Sets the labels using integer values
lblCorrectNum.Text = iCorrectACount.ToString();
lblWrongNum.Text = (iCurrentQIndex - iCorrectACount).ToString();
lblScoreTotal.Text = (iCorrectACount * modifier).ToString();
}
Maybe this has something to do with why lblScoreTotal.Text will not change to the value * modifier but will on another form?
The reason I asked this question here is because someone advised me to disable warning messages but I didn't think that was the appropriate solution?
Thanks.
The compiler is entirely correct: nothing is going to change your m_difficulty field, as far as you've shown. What do you expect to set that value? Did you actually mean to set it to something based on MainForm as per iCorrectACount and iCurrentQIndex?
How do you expect it would ever be anything other than whatever (Difficulty) 0 evaluates as?
It's pretty dodgy to be pulling initial values from a statically-accessed instance of a form, too, IMO. It would be much better if the constructor accepted initial values from whatever was constructing it.
m_difficulty is private, so it can't be accessed from outside your class, but you never assign it inside, so it will never change.
Therefore, it makes no real sense to compare it, as it will always be equal to 0.
You should always initialize a variable after you declared it.
private Difficulty m_difficulty = new Difficulty();
Something like that.
So you prevent it to be null (in this case you would get an exception).
The warning just tells you this.
It sounds to me like you're expecting m_difficulty to be bound to a dropdown selection on your user form. It is not. Even if it were, you would want to access the SelectedValue property instead of the object itself. Maybe this is what you're looking for.
Difficulty m_difficulty = (Difficulty)Enum.Parse(ddDifficulty.SelectedValue);
I don't know the correct technical terms to describe my question, so I'll give an example:
private Point _PrivateVect = new Point();
public Point Publicvect
{
get
{
return _PrivateVect;
}
set
{
_PrivateVect = value;
}
}
The problem is that if I wanted to access Publicvect.X I get the error Cannot modify the return value of 'Publicvect' because it is not a variable. Is there a way around this? Or do I just need to do Publicvect = new Point(NewX, Publicvect.Y); forever?
Yet another reason that mutable structs are evil. One workaround is to expose the dimensions as accessors for convenience:
public Point PublicX {
get {return _PrivateVect.X;}
set {_PrivateVect.X = value;}
}
public Point PublicY {
get {return _PrivateVect.Y;}
set {_PrivateVect.Y = value;}
}
But other that this; yes you would need to do the new Point(x,y) each time, since Point is a struct. When you access it via a property you get a copy of it, so if you mutate the copy and then discard the copy, you simply lose the change.
The problem you have here is that the Point type is a Value Type. So when you manipulate Pointvect.X you are really manipulating a temporary copy of the value type, which of course has no effect on the original instance.