For example, I have MonoBehaviour derived class called Foo:
class Foo : MonoBehaviour {
public Button lastButton;
public Image []images;
}
[CustomEditor(typeof(Foo))]
class FooEditor : Editor {
public override void OnInspectorGUI()
{
DrawDefaultInspector();
Foo foo = (Foo)target;
if(GUILayout.Button("Bind last Button and all Images")) {
/* how to bind programatically last foo.GetComponentsInChildren<Button>();
to foo.gameObject.scene's
foo.gameObject.GetComponent<Foo>().lastButton
in edit mode's property window
(without have to drag on the editor)?
*/
/* and how to bind programatically all foo.GetComponentsInChildren<Image>();
to foo.gameObject.scene's
foo.gameObject.GetComponent<Foo>().images
in edit mode's property window
(without have to drag all one by one)?
*/
}
}
}
I want to automate the binding without have to drag one by one or do it in runtime, how can I do it programatically?
the only workaround I can think of (if there's no such API) is by saving the scene, parsing the scene yaml, then update the binding on the yaml file, and force UnityEditor to reload the yaml, but not sure if it's gonna work since loading yaml and rewriting it doesn't give equal value
Though I still don't understand the purpose of "binding" to be honest, it seems to me you actually are talking about simply referencing all the components via the editor script instead of having to drag and drop them. (Maybe the binding is included here and I just don't know it under that name?)
First of all make sure that either the entire code for FooEditor is placed in a folder called Editor or wrap it in
#if UNITY_EDITOR
// any code using UnityEditor namespace
#endif
in order to strip them off in a build later. Otherwise you'll get compiler errors since UnityEditor will not exist in a build.
Then the important thing is to allways manipulate the SerializedPropertys of the SerializedObjects in editor scripts. This handles all the marking as dirty, saving changes and Undo/Redo entries for you. If you should happen to manipulate rather the fieds directly you would have to take care of these things yourself ...
a keyrole herefore play SerializedObject.Update and SerializedObject.ApplyModifiedProperties for loading and writing back values between the real target component and its serialized object - I like to call it "shadow clone".
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.UI;
class Foo : MonoBehaviour
{
public Button lastButton;
public Image[] images;
}
#if UNITY_EDITOR
[CustomEditor(typeof(Foo))]
class FooEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
// fetch current values from the real target into the serialized "clone"
serializedObject.Update();
Foo foo = (Foo)target;
if (GUILayout.Button("Bind last Button and all Images"))
{
// get last button field as serialized property
var lastButtonField = serializedObject.FindProperty("lastButton");
// get last Button reference
// pass true to also get eventually inactive children
var buttons = foo.GetComponentsInChildren<Button>(true);
var lastButton = buttons[buttons.Length - 1];
// asign lastButton to the lastButtonField
lastButtonField.objectReferenceValue = lastButton;
// slightly more complex but similar
// get the field as serialized property
var imagesField = serializedObject.FindProperty("images");
// get the images references
// again pass true to also get eventually inactive ones
var images = foo.GetComponentsInChildren<Image>(true);
// now first set the according list size
imagesField.arraySize = images.Length;
// assign all references
for (var i = 0; i < imagesField.arraySize; i++)
{
// serialized property of the element in the field list
var entry = imagesField.GetArrayElementAtIndex(i);
// simply assign the reference like before with the button
entry.objectReferenceValue = images[i];
}
}
// write back changes to the real target
// automatically handles marking as dirty and undo/redo
serializedObject.ApplyModifiedProperties();
}
}
#endif
I hope I'm not completely off and this is what you ment by "binding".
Note if you want to further change values of a reference you optained which is not the target itself you can easily use new SerializedObject(objectReference) in order to get a serialzed object e.g.
var serializedLastButton = new SerializedObject (lastButton);
Or also
var serializedLastButton = new SerializedObject(lastButtonField.objectReferenceValue);
now when changing any field in it again using FindProperty(propertyName) make sure to again also use
serializedLastButton.Update();
// make changes
serializedLastButton.ApplyModifiedProperties();
Related
So I created a method to populate the inventory system I have created in Unity, however I can't seem to figure out a way to order them in alphabetical order. Each button is created as a child of the button holder panel which is a game object variable. This method is called whenever the player picks something up.
private void Populate_Inventory ( )
{
Button btn_CurrentItem;
int int_Count;
for ( int_Count = int_PreviousCount; int_Count < strList_Inventory.Count; int_Count++ )
{
btn_CurrentItem = Instantiate ( btn_Item, pnl_ButtonHolder.transform );
btn_CurrentItem.name = strList_Inventory [ int_Count ];
btn_CurrentItem.GetComponentInChildren<Text> ( ).text = strList_Inventory [ int_Count ];
btn_CurrentItem.gameObject.AddComponent<Inventory_Item> ( );
btn_CurrentItem.GetComponent<Inventory_Item> ( ).str_Name = cls_Pickup.str_PickupName;
btn_CurrentItem.GetComponent<Inventory_Item> ( ).str_Information = cls_Pickup.str_PickupInformation;
int_PreviousCount = int_Count;
}
int_PreviousCount++;
}
If anyone can help it would be very appreciated.
Jonathan Palmer
The primary issue with this approach is that you're adding single buttons at a time whenever you pick up an item, and those buttons are created as children of the pnl_ButtonHolder object, but your method has no knowledge of previous buttons that have been created.
Option 1 (Bad)
You can use the GetComponentsInChildren<Button>() method on the pnl_ButtonHolder object to get all of the button components that have been previously created once you've added a new button, and then sort your buttons according to their name.
This isn't ideal as GetComponentsInChildren<>() is an expensive method, and doesn't make use of the idea of an Inventory very well.
Option 2 (Good)
Create an Inventory class that manages your actual inventory, including sorting items. It might look something like this:
public class Inventory_Button : MonoBehaviour
{
public Button button = default;
public void Initialize(Intenvory_Item item)
{
button.name = item.name;
// Other work here.
}
}
public class Inventory : MonoBehaviour
{
public GameObject inventoryItemPrefab = default;
public Transform inventoryParent = default;
private List<Inventory_Item> _inventory = new List<Inventory_Item>();
private List<Inventory_Button> _inventoryButtons = new List<Inventory_Button>();
public void AddItem(Intenvory_Item item)
{
_inventory.Add(item);
Inventory_Button button = GameObject.Instantiate(inventoryItemPrefab, inventoryParent).GetComponent<Inventory_Button>();
button.Initialize(item);
_inventoryButtons.Add(button);
_inventoryButtons.Sort((x, y) => x.name.CompareTo(y.name));
}
public void RemoveItem(Inventory_Item item)
{
// Do work to remove the item.
}
}
This kind of setup is useful for several reasons:
Your inventory management is now handled by a single class rather than a collection of objects. This makes it easy to interact with.
It will make removing items much easier in the future. With your current implementation, it looks like you'd have a difficult time removing an item from the player's inventory.
It separates responsibility between an Inventory class, an Inventory_Item class, and an Inventory_Button class, each of which stands on its own and works together.
A few final notes:
I've left out some details in the two classes above. You should fill them in to fit the needs of your game.
You can be more efficient with sorting by using something like Insertion Sort. This solution will get the job done.
Using prefixes for naming your variables can be quite confusing to people trying to read your code. I recommend you check out a style guide. There's a great one here.
I need to instantiate an object at runtime, where the number of objects are based on a txt file (number of lines). All objects need to be clickable (onClick() event) and when they are pressed a tooltip must appear. Tooltips are specific ( Object1 -> Tooltip1, Object2 -> Tooltip2). Tooltips are just a Panel and they consist in some other Panels and Buttons. One of these create a new Panel. Also these Panel are specific (Tooltip1 -> Panel1 and so on). I create a prefab for each of three objects.
So, Object1 - onClick() -> Tooltip1 - onClick() -> Panel1. At runtime.
How can I keep reference of an object create at runtime?
My first solution:
Create a Empty object and assign a script to it with a public variable (Object prefab).
Instantiate Object prefab:
for (int i = 0; i < numberOfObject; i++)
{
var instance = Instantiate(m_ObjectPrefab);
instance.name = "Object_" + m_nameObject[i];
Instantiate one Tooltip for each Object:
var instancePanelTooltip = Instantiate(m_panelTooltipPrefab, m_canvas.transform);
instancePanelTooltip.name = "Panel_Tooltip_" + m_nameObject[i];
Instantiate one Panel for each Tooltip:
var instancePanel = Instantiate(m_panelPrefab, m_canvas.transform);
instancePanel.name = "Panel_" + m_nameObject[i];
instancePanel.SetActive(false);
instancePanelTooltip.SetActive(false);
Add event handler for Object
DetectClickOnObject scriptDetectClickPanelTooltip = instance.AddComponent<DetectClickOnObject>();
scriptDetectClickPanelTooltip.SetTooltip(instancePanelTooltip);
Add event handler for button on Tooltip
DetectClickOnObject scriptDetectClickPanel = buttonOpenPanel.AddComponent<DetectClickOnObject>();
scriptDetectClickPanel.SetPanel(instancePanel);
}
Issue with this solution:
I will instantiate 3 object (Object, Tooltip, Panel) for each line of file. For Object it is okay, but it is not with Tooltip and Panel, because only one Tooltip is active among all (same for Panel).
I just avoid the problem of reference because I create in the same place all objects (one for each element), but what can I do if I need to get access to Tooltip2 or Panel3 without a reference (I am trying to avoid Find and similar).
Conclusion of the first solution: Solution is working, but I think there is a better way of doing that (avoid create so much object and keep reference in the right way).
My second solution (guidelines):
I am trying to create a class to keep reference of all object create at runtime.
I want to create an instance of Object for each lines, but I want just one Tooltip and Panel for all Object and changing properties according to Object clicked. So Object is create at runtime, but Tooltip and Panel are already in the scene but not active.
I need a Register Event Manager to add onClick() event at runtime on Objects and it need to handle properties to be set on Tooltip and Panel based on clicked Object.
Problems with second solution: Referring to 1) I tried to follow that, but I ended up with nothing. I am lost between singleton, static and something else. Referring to 2) I think it can be easy, I just need to cut away some of the first solution. Referring to 3) I can not do more if I do not have a class reference manager.
What I am looking for:
Is first solution so bad? If I look at code I am disgusted by it, it is far away from elegance (or something similar).
Can you suggest me how can I keep track of reference create at runtime with a Reference Manager? And how use it?
#Behnam Sattar suggestion:
As DataModell class,
public class DataModelPOI
{
public string m_namePOI { get; private set; }
public string m_locationPOI { get; private set; }
public Vector2d m_positionPOI { get; private set; }
public GameObject m_gameObject_POI;
public GameObject m_gameObjectTooltip;
public GameObject m_gameObjectPanel;
public DataModelPOI(string namePOI, string locationPOI, Vector2d positionPOI)
{
this.m_namePOI = namePOI;
this.m_locationPOI = locationPOI;
this.m_positionPOI = positionPOI;
}
}
As DataManager,
public class POIManager : MonoBehaviour
{
List<DataModelPOI> dataCollectionPOI = new List<DataModelPOI>();
void Start()
{
ReadFile();
SpawnPOI();
}
void Update()
{
int count = dataCollectionPOI.Count;
for (int i = 0; i < count; i++)
{
UpdatePOIPosition();
}
}
void ReadFile()
{
TakeDataFromFile();
for (int i = 0; i < ength; i++)
{
DataModelPOI dataPOI = new DataModelPOI(m_namePoi[i], m_namePoi[i], _locations[i]);
dataCollectionPOI.Add(dataPOI);
}
}
private void SpawnPOI()
{
for (int i = 0; i < dataCollectionPOI.Count; i++)
{
DataModelPOI dataPOI = dataCollectionPOI[i];
var instance = Instantiate(m_POIPrefab);
instance.name = "POI_" + m_namePoi[i];
dataPOI.m_gameObject_POI = instance;
dataPOI.m_gameObjectTooltip = m_panelTooltipPOI;
dataPOI.m_gameObjectPanel = m_panelPOI;
}
}
Now I need to register Event associate to GameObject instantiate before. I want to do that in my EventManager. How can I point to dataCollectionPOI in EventManager class created and feeded in DataManager? Thanks for your time.
Based on my understanding your question is mostly a design question. In first part of this answer, I'm giving you a suggestion for doing the design and keeping a reference to your objects. In second part I'll give you some tips regarding performance.
[I'm using RootObject instead of Object to refer you the main GameObject you create.]
Design
Let's break down our needs and then come up with a solution for each.
First we want to read some text file and then get some data from that. This data will be used later for creation of GameObjects. For now let's just focus on the data itself.
What we want here is a manager class which reads the file for us and stores the data in some form. We access this manager later and ask for our data in order to create the GameObjects.
This manager class stores our data in a collection of data objects [notice here we're talking about plain objects and not Unity's GameObjects]. You need to design this data class based on each line of text you have. Optionally, you can also keep the references to GameObjects here too.
Assume you're reading three string values from each line, named ValueOne, ValueTwo, and ValueThree, and you want to keep reference to three GameObjects called RootObject, ToolTip and Panel. For such purpose you can define following class:
public class DataModel {
// Values read from text file.
public string valueOne { get; private set; }
public string valueTwo { get; private set; }
public string valueThree { get; private set; }
// Placeholders for GameObjecs created at runtime.
public GameObject rootObject;
public GameObject tooltipObject;
public GameObject panelObject;
public DataModel(string valueOne, string valueTwo, string valueThree){
this.valueOne = valueOne;
this.valueTwo = valueTwo;
this.valueThree = valueThree;
}
}
Then in your manager class you can create a collection (a List for example) for holding your data. Your manager class should read the text file at some point and populate this list with instances of DataModel. It will be something like this:
public class DataManager {
List<DataModel> dataCollection = new List<DataModel>();
public void ReadFile() {
// Here you need to read the file and get the values you need.
// The actual code should be different from what I'm putting here.
foreach(string line in lines) {
// You get valueOne, valueTwo and valueThree
// from each line and maybe prepare them
// (maybe you need conversion from string to int)
DataModel data = new DataModel(valueOne, valueTwo, valueThree);
dataCollection.Add(data);
}
}
}
After you call the method on manager to read the data, you'll have your data prepared for you whenever you want to use it.
It's time to create objects based on the data and save the reference.
for (int i = 0; i++; i <= manager.dataCollection.Count) {
DataModel data = manager.dataCollection[i];
data.rootObject = instantiate() // You instantiate the root GameObject here.
data.tooltip = instantiate() // You instantiate the tooltop GameObject here.
data.panel = instantiate() // You instantiate the panel GameObject here.
}
Done. Now you have a manager class which has reference to all the data and also GameObjects which are created based on this data.
Performance
It might not be a good idea to do this all in runtime as it might cause frame drops in your game. If this is a problem you can try object pooling. If you search for that you should be able to find great tutorials on how to perform object pooling.
If you ended up not using object pooling, you can still remedy any performance drops by instantiating only one GameObject per frame. This can be done using Coroutines. You just need to do a yield return new WaitForEndOfFrame() in your loop of instantiation.
Final Note
Keep in mind that this all a suggestion and I don't think there is one single best answer to your question. Make sure you try to understand what tools are at your disposal and try them all before deciding on one solution. :)
You're basically on the right track, but you can separate (or 'objectify' ;) what scripts keep what references. Keep scripts that manage the internal workings of your prefabs in those prefabs.
A singleton-like pattern for the Tooltips is definitely the way to go. For where you can't use a singleton, such as in the clickable objects, use something more akin to dependency injection (to save on Finds) and pre-stored reference:
var obj = Instantiate(...);
obj.GetComponent<SomeManagerScript>.SomeDependency = SingletonInstance;
obj.GetComponent<StoredReferenceScript>.TextPanel.Text = "Some Text";
As to events, you can handle them a couple of ways. One, each clickable manages its own bindings/functionality; or two, each clickable notifies a global manager that it was clicked on, and the manager determines the actions to take.
Basically you need to create an object at Runtime and set the data for that specific object.
here is the simplest way to do that
first of all create scripts first one can Create an object at runtime and second one is your data setter script that attach with your prefab
so, when ever you create an object at runtime you can pick a reference of the dataSetter and set the specific data.
Hope below given code may useful to you.
GameObject object = Instantiate(gameObject,parent)
DataSetter s = object.GetComponent<DataSetter>().toolTip = "YourTooltip";
in DataSetter script tool tip is a string variable.
you can also declare text variable and assign a text to that.
I'm trying to customize the Windows Forms Designer's code generation for InitializeComponent. The MSDN article "Customizing Code Generation in the .NET Framework Visual Designers" contains a section "Controlling Code Generation" that explains the basics of how this can be done.
I've closely followed an example in the above article:
//using System.ComponentModel.Design.Serialization;
class SomeFormSerializer : CodeDomSerializer
{
public override object Serialize(IDesignerSerializationManager manager,
object value)
{
// first, let the default serializer do its work:
var baseSerializer = (CodeDomSerializer)manager.GetSerializer(
typeof(Form).BaseType, typeof(CodeDomSerializer));
object codeObject = baseSerializer.Serialize(manager, value);
// then, modify the generated CodeDOM -- add a comment as the 1st line:
if (codeObject is CodeStatementCollection)
{
var statements = (CodeStatementCollection)codeObject;
statements.Insert(0, new CodeCommentStatement("CODEDOM WAS HERE"));
}
// finally, return the modified CodeDOM:
return codeObject;
}
}
Now I hook this up to my form SomeForm:
[DesignerSerializer(typeof(SomeFormSerializer), typeof(CodeDomSerializer))]
class SomeForm : Form { … }
The Forms Designer might then generate the following InitializeComponent code:
private void InitializeComponent()
{
… /* (general setup code, such as a call to `this.SuspendLayout`) */
//
// someButton
//
… /* (someButton's properties are set) */
// CODEDOM WAS HERE!
//
// SomeForm
//
… /* (form's properties are set) */
… /* (general setup code, such as a call to `this.ResumeLayout`) */
}
Note that the comment // CODEDOM WAS HERE was not added as the very first line in InitializeComponent, but only as the first line of the code block that deals with the properties of the form object itself.
What would I have to do if I wanted to be able to modify the generated CodeDOM of the whole method, and not just of the part that deals with a specific object?
Background: Why do I want to do this? In Windows Forms, if one wants flexible value conversion during data binding, one usually has to resort to subscribing to the Format and Parse events of some particular Binding object. So I'm creating a specialized Binding subclass (let's call it ConvertingBinding) that simplifies this process a bit.
Now, the issue is that when data bindings are set up in the Windows Forms Designer, the generated code creates instances of Binding; however, I would want the designer to instantiate my specialized subclass instead. My current approach is to let the designer create a CodeDOM tree first, then walk that tree and replace all instantiations of Binding by instantiations of ConvertingBinding.
You need to create two Form class. First Form with a DesignerSerializerAttribute. Second Form is descendant from first. After that you can customize InitializeComponent() for second Form and it's controls or components.
For this you should use manager.Context to get all StatementContext and CodeStatementCollection objects that contains serialized code of Form's controls.
Here is some simple steps.
Include libraries:
using System.CodeDom;
using System.ComponentModel.Design.Serialization;
using System.Collections;
Create new form and add DesignerSerializerAttribute:
[DesignerSerializer(typeof(CustomFormSerializer), typeof(CodeDomSerializer))]
class CustomForm : Form { … }
Create CustomForm descendant and add some controls or components to it:
class CustomForm1 : CustomForm { … }
Add method to CustomFormSerializer for processing CodeStatementCollection, for example:
private void DoSomethingWith(CodeStatementCollection statements)
{
statements.Insert(0, new CodeCommentStatement("CODEDOM WAS HERE"));
}
In Serialize method use cycle through manager.Context:
public override object Serialize(IDesignerSerializationManager manager,
object value)
{
//Cycle through manager.Context
for (int iIndex = 0; manager.Context[iIndex] != null; iIndex++)
{
object context = manager.Context[iIndex];
if (context is StatementContext)
// Get CodeStatementCollection objects from StatementContext
{
ObjectStatementCollection objectStatementCollection =
((StatementContext)context).StatementCollection;
// Get each entry in collection.
foreach (DictionaryEntry dictionaryEntry in objectStatementCollection)
// dictionaryEntry.Key is control or component contained in CustomForm descendant class
// dictionartEntry.Value is CodeDOM for this control or component
if (dictionaryEntry.Value is CodeStatementCollection)
DoSomethingWith((CodeStatementCollection)dictionaryEntry.Value);
}
//Do something with each collection in manager.Context:
if (context is CodeStatementCollection)
DoSomethingWith((CodeStatementCollection)context);
}
// Let the default serializer do its work:
CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
GetSerializer(value.GetType().BaseType, typeof(CodeDomSerializer));
object codeObject = baseClassSerializer.Serialize(manager, value);
// Then, modify the generated CodeDOM:
if (codeObject is CodeStatementCollection)
DoSomethingWith((CodeStatementCollection)codeObject);
// Finally, return the modified CodeDOM:
return codeObject;
}
I am trying to get a StringElement's 'Value' to update in the UI when I set it after already setting up the DVC.
e.g:
public partial class TestDialog : DialogViewController
{
public TestDialog() : base (UITableViewStyle.Grouped, null)
{
var stringElement = new StringElement("Hola");
stringElement.Value = "0 Taps";
int tapCount = 0;
stringElement.Tapped += () => stringElement.Value = ++tapCount + " Taps";
Root = new RootElement("TestDialog")
{
new Section("First Section")
{
stringElement,
},
};
}
}
However the StringElement.Value is just a public field, and is only written to the UICell during initialization when Element.GetCell is called.
Why isn't it a property, with logic in the setter to update the UICell (like the majority of Elements, e.g. EntryElement.Value):
public string Value
{
get { return val; }
set
{
val = value;
if (entry != null)
entry.Text = value;
}
}
EDIT :
I made my own version of StringElement, derived from Element (basically just copied the source code from here verbatim)
I then changed it to take a class scoped reference to the cell created in GetCell, rather than function scoped. Then changed the Value field to a property:
public string Value
{
get { return val; }
set
{
val = value;
if (cell != null)
{
// (The below is copied direct from GetCell)
// The check is needed because the cell might have been recycled.
if (cell.DetailTextLabel != null)
cell.DetailTextLabel.Text = Value == null ? "" : Value;
}
}
}
It works in initial testing. However I am not sure on whether taking a reference to the cell is allowed, none of the other elements seem to do it (they only take references to control's placed within the cells). Is it possible that multiple 'live'* cell's are created based on the one MonoTouch.Dialog.Element instance?
*I say live to indicate cells currently part of the active UI. I did notice when navigating back to the dialog from a child dialog the GetCell method is invoked again and a new cell created based on the Element, but this is still a 1-1 between the element and the live cell.
For the main question:
Why does MonoTouch.Dialog use public fields for some Element options, and public properties for others?
I've been through the code, and I don't think there's a consistent reason for use of either.
The Dialog project was not part of the MonoTouch project initially - I don't think Miguel knew how useful it was going to turn out when he started wrote and grew it - I think he was more focussed on writing other apps like TweetStation at the time.
I know of several people (including me!) who have branched the code and adapted it for their purposes. I would guess at some future point Xamarin might write a 2.0 version with stricter coding standards.
Taking references to live cells
For limited use you can do this... but in general don't.
The idea of the table view is that cells get reused when the user scrolls up and down - especially in order to save memory and ui resources. Because of this is a long list, multiple elements might get references to the same cell.
If you do want to cache a cell reference then you probably should override GetCell() so that it never tries to reuse existing cells (never calls DequeueReusableCell)
Alternatively, you could try to change some code in the base Element class in order to find out if the Element has a current attached cell - this is what CurrentAttachedCell does in my branch of Dialog https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross.Dialog/Dialog/Elements/Element.cs (but that branch has other added functions and dependencies so you probably won't want to use it for this current work!)
I'm new in C# but not new to coding --being doing it for almost two decades--, and have a problem with properties in a custom control I'm building, which inherits from a Panel. When I put my properties, I can see them in the Designer properties list and can even set them, but when running my little application, it seems these properties values are not used. The same if I change a property programatically: no error but my control does nothing, it is like they are not properly set. However, if I do it programatically whithin the class, they do work. My guess is that something in my properties set/get stuff is not right. Please see the following code chunk of how I'm doing it:
public class ColorStrip : Panel
{
// properties
// ------------------------------------------
// size of color clusters (boxes)
private int _clusterSize = 20;
// controls if show the buttons panel
private Boolean _showButtons;
// property setters/getters
// ------------------------------------------
// clusterSize...
public int clusterSize
{
get { return _clusterSize; }
set { _clusterSize = value; }
}
// showButtons...
public Boolean showButtons
{
get { return _showButtons; }
set { Console.Write(_showButtons); _showButtons = value; }
}
....
So in my form, for instance in the load or even in a click event somewhere, if I put colorStrip1.showButtons = false; or colorStrip1.showButtons = true; whatever (colorStrip1 would be the instance name after placing the control in the form in design mode)... console.write says always 'false'; Even if I set it in the design properties list as 'true' it will not reflect the settled value, even if I default it to true, it will never change externally. Any ideas? Non of the methods get the new and externally settled property value neither, obviously the getter/setter thing is not working. Seems to me I'm not doing right the way I set or get my properties outside the class. It works only inside it, as a charm...Any help...very appreciate!
Cheers
lithium
p.s. TO CLARIFY SOLUTION:
Setting the property in this case didn't work because I was trying to use a new set value within the constructor, which seems can't get the new values since it is, well, building the thing. If I change the property value in Design mode > Property editor or in code externally to the object, say in it's parent form's load event, it will change it but readable for all methods except the constructor, of course :)
It's likely an issue of the order of execution. Your property setter just sets a variable, but doesn't actually trigger anything on the control to update the state related to this variable (e.g. adding or showing the buttons I assume).
When you set the property befre the rest of the initialization is done, the value is being used, otherwise it isn't because during the initial go the default value is still the property value.
You need to act on the setter, here's some pseudocode to illustrate:
set {
_showButtons = value;
if (alreadyInitialized) {
UpdateButtons();
}
}
Note: make sure to first set the value, then act - otherwise you end up using the old value (just like your Console.Write() is doing).
The quoted code doesn't look problematic. Are you sure you're referencing the same instance of ColorStrip? Also, check your .Designer.cs file to ensure that the code setting the property is there.
In fact, try simplifying your code by using auto-implementing properties:
public int clusterSize { get;set;}
public Boolean showButtons {get;set;}
public ColorStrip() { ... clusterSize = 20; ... }