Check when a variable has changed in Custom Editor - c#

I am attempting to check whether any variable has changed in a custom Editor Class, but I can't seem to get a result from the check. This is my custom editor class. I am using EditorGUI.BeginChangeCheck() & EditorGUI.EndChangeCheck():
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(TileManager))]
[CanEditMultipleObjects]
public class TileManagerEditor : Editor
{
public override void OnInspectorGUI()
{
TileManager tileManager = (TileManager)target;
EditorGUI.BeginChangeCheck();
serializedObject.Update();
tileManager.tileCount = (int)Mathf.Clamp(EditorGUILayout.IntField("Tile Count", tileManager.tileCount), 0, Mathf.Infinity);
tileManager.resizeTileCount = EditorGUILayout.Toggle("Resize Tile Count", tileManager.resizeTileCount);
tileManager.tileSize = EditorGUILayout.Vector3Field("Tile Size", tileManager.tileSize);
tileManager.tileSpacing = Mathf.Clamp(EditorGUILayout.FloatField("Tile Spacing", tileManager.tileSpacing), 0, Mathf.Infinity);
tileManager.relativeSpacing = EditorGUILayout.Toggle("Relative Spacing", tileManager.relativeSpacing);
if (tileManager.relativeSpacing == true)
{
tileManager.spacingMultiplier = Mathf.Clamp(EditorGUILayout.FloatField("Spacing Multiplier", tileManager.spacingMultiplier), 0, Mathf.Infinity);
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("tilePrefab"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("tileHolder"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("tiles"), true);
serializedObject.ApplyModifiedProperties();
if (EditorGUI.EndChangeCheck())
{
tileManager.UpdateOnChange();
}
}
}
I have also tried Debug.Log(EditorGUI.EndChangeCheck()) instead of the if statement, but I don't get an output

There are two ways to track "something has changed" I can think off.
Both I would solve via a custom generic class changeTrackableValue<T> (a value where you can track changes). In both case you need a way to decide when all changes have become the "new normal".
Option 1 - Comparative
You keep a know "good" value. If the current and the know "good" value do not match, valueChanged would return true.
Properties:
if you take the long route back to the original value, it would read as "unchanged". usually adviseable for a Text Editor
It would basically double your memory demand, if not more then that (if parts are cut or added wholesale)
the original value does not need to be a property
Option 2 - the archive Bit
I copy that from the Filesystem. You use a property with a custom set for the value. You store one bool changed = false with each value. If the value is changed via set function, you set changed = true.
Properties:
minimal increase in memory useage
any change is tracked, even the ones back to the original state (can be good or bad)
you need a property with a public set and need to be able to modify said setter.
I can provide code for either one, if you need it.

Related

Drop-down list in properties window to start at certain index

Background information:
We have a UserControl called Sensor.
Sensor has a property called SlaveSensor.
The type of the property SlaveSensor is Sensor.
public Sensor SlaveSensor;
{
get
{
return _slaveSensor;
}
set
{
//Some more code for checking various stuff...
_slaveSensor; = value;
}
}
As you can see, the type of the property is the same as the UserControl itself.
The property SlaveSensor is normally set via the properties window during design time.
Visual Studio automatically provides the editor as a drop-down list, from which one can select from all available Sensors on the form.
My question is:
How can I make the drop-down list start at a specified instance in the list,
to make it quicker to find the right Sensor to set for the property?
The name of the Sensor to set as the property is always nearly the same as the name of the Sensor for which the property is being set.
So if e.g. the drop-down list would simply auto scroll to the index in the list that has the name of the Sensor for which the property is being set,
I have achieved my goal.
What do I have so far:
I assume that I need to implement a custom property editor.
I might actually be able to create one with a drop-down list, and fill this with strings,
but the existing is OK as it is, I just need to tell it to drop-down to a certain index when clicked.
Thanks for any help in advance!
I'd try this.
string text = "SomeText";
var item = dropdown.Items.FindByText(text);
if(item!= null)
item.Selected = true;
Or by value:
string value = "SomeValue";
var item = dropdown.Items.FindByValue(value);
if (item != null)
item.Selected = true;
Taken from top answer here

Question about PhotonNetwork.CurrentRoom.CustomProperties

When the game starts in multiplayer, the master client sends a PunRPC to have all clients run a function. This function tries to get the room properties to see if the game is active, if so it does something. For some reason a client gets a null reference error, but the master client does not. The strange thing is, a debug of the hash table for room properties is visible but I cannot get a specific item in it.
Tried Debugging the hash table to make sure that the key was set when the code was run. It was. "(System.String)ag=(System.Boolean)True ag=activeGame" This shows in Debug.Log(hash); But (bool)hash[rpk.activeGame] gets a null reference error. But only on the client side not the master client. So the key also works.
// Call all the clients to set up the room settings in the sub menu.
[PunRPC]
private void GameRoomSetup (string pOne, string pTwo, int pOneColor, int pTwoColor)
{
GameObject gameMenu = GameObject.Find ("GameMenu");
gameMenu.GetComponent<SubMenu> ().UpdatePlayers (pOne, pTwo, pOneColor, pTwoColor);
gameMenu.GetComponent<SubMenu> ().StartGameSetup ();
// If you are a player, change the active buttons that are visible.
if (PhotonNetwork.NickName == pOne || PhotonNetwork.NickName == pTwo)
{
gameMenu.GetComponent<GameButtonManager> ().GameStart ();
}
hash = PhotonNetwork.CurrentRoom.CustomProperties;
Debug.Log(hash);
if ((bool)hash[rpk.activeGame]) // Error on this line on client but not on master client. Says null reference.
{
GameObject.Find ("SoundManager").GetComponent<SoundManagerScript> ().PlayBackgroundTwo ();
GameObject.Find ("GameMenu").GetComponent<SubMenu> ().ChangeSubMenuActive (false);
}
}
I'm trying to run my if statement as a client but I get an error.
Thank you for choosing Photon!
To get a custom property, I recommend you use TryGetValue method as follows:
hash = PhotonNetwork.CurrentRoom.CustomProperties;
object temp;
string key = rpk.activeGame;
if (hash.TryGetValue(key, out temp))
{
if (temp is bool)
{
bool activeGame = (bool)temp;
}
else
{
// unexpected custom property value type
}
}
else
{
// custom property not found
}
If the custom property is not available yet, wait for the callback IInRoomCallbacks.OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) (reference API).
Other notes and recommendations:
private void GameRoomSetup (string pOne, string pTwo, int pOneColor, int pTwoColor)
Not sure if it's supported or if it's a good idea to pass multiple parameters to a PUN RPC method.
To debug log a Dictionary or a Hashtable you could make use of SupportClass.DictionaryToString() method.
so instead of
Debug.Log(hash);
use
Debug.Log(SupportClass.DictionaryToString(hash));
Avoid calling expensive methods like GameObject.Find:
GameObject gameMenu = GameObject.Find ("GameMenu");
Also here you have duplicate calls to gameMenu.GetComponent<SubMenu>(), at least call it once and cache the component result found if any.
gameMenu.GetComponent<SubMenu> ().UpdatePlayers (pOne, pTwo, pOneColor, pTwoColor);
gameMenu.GetComponent<SubMenu> ().StartGameSetup ();
Comparing strings should not be done using == operator. At least use Equal method and proper StringComparison type. Read "How to compare strings in C#".
// If you are a player, change the active buttons that are visible.
if (PhotonNetwork.NickName == pOne || PhotonNetwork.NickName == pTwo)
{
gameMenu.GetComponent<GameButtonManager> ().GameStart ();
}
Besides, why do you use the Nickname to check if it's player one or two? maybe use ActorNumber or a custom player index. Or use the player count if the room is for 2 players only.

Android Preference. Setting child default value when parent is disable

I'm working on simple Android application. I'm using C# and Xamarin but i believe that programing language doesn't matter in that case since all changes are in .xml file.
Ok so my problem is related with preference that have dependency to other preference. First let me show my code then I will try to explain what i asking about.
<PreferenceCategory
android:title="#string/Pref_battery_settings"
android:key="pref_key_battery_settings">
<SwitchPreference
android:title="#string/Pref_battery_track_title"
android:summary="#string/Pref_battery_track_summary"
android:key="Pref_battery_track"
android:defaultValue="true"/>
<CheckBoxPreference
android:dependency="Pref_battery_track"
android:disableDependentsState="true"
android:title="#string/Pref_battery_track_battery_status_title"
android:summary="#string/Pref_battery_track_battery_status_summary"
android:key="Pref_battery_track_status"
android:defaultValue="false"/>
As You can see i have 2 preference. First Pref_battery_track is SwitchPreference that will determine is my app will track battery ( levels ect. ) If that preference will be setted to TRUE user will be able to use second preference which will decide if we want to track battery status or nor ( status is e.g Charging, Discharging ect.). In logical thinking if we set first preference to true we can decide do we want to track more information or not but right now i have problem. When i set Pref_battery_track to true then Pref_battery_track_status also to true and switch back first preference to false second will be still as true and we will be able to do code like :
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
var t = prefs.GetBoolean("Pref_battery_track_status", false);
This code will return true when Pref_battery_track_status will be true even when Pref_battery_track will be fasle. So my question is : Is there any way to set child preference to default value when parent preference is false ?
Hope you know what i asking about.
And yes i know that i can simply check before i use child preference like`
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
if(prefs.GetBoolean("Pref_battery_track", false))
{
var t = prefs.GetBoolean("Pref_battery_track_status", false);
// Do things
}`
But this solution is not nice since every time before i use child preference i will have to check parent.
You can subscribe the PreferenceChange event of your SwitchPreference, for example like this:
var switchp = PreferenceScreen.FindPreference("Pref_battery_track");
switchp.PreferenceChange += Switchp_PreferenceChange;
And then in Switchp_PreferenceChange set the Checked property of CheckBoxPreference for example:
private void Switchp_PreferenceChange(object sender, PreferenceChangeEventArgs e)
{
var isenabled = (bool)e.NewValue;
if (!isenabled)
{
var checkp = PreferenceScreen.FindPreference("Pref_battery_track_status") as CheckBoxPreference;
checkp.Checked = false;
}
}

Can't seem to change properties of objects in winforms C#

This is a bit of a confusing scenario. Basically, I'm trying to set a button's color when I use setter for a private variable that I store its color in.
First off, I have a seperate window for customizing stuff. When I change the button color, I want to change every button in this window as well. I have it stored in a static variable in my main form class.
public static frm_custom customizer;
This is the setter for the variable in question.
private Color _buttonColor;
public Color buttonColor
{
get { return this._buttonColor; }
set
{
this.btn_input.BackColor = buttonColor;
this._buttonColor = buttonColor;
if (Application.OpenForms.OfType<frm_custom>().Count() == 1)
{
customizer.setButtonColor(buttonColor);
}
}
}
Strangely, it doesn't effect the color at all. Did I do something wrong?
Did I do something wrong?
Yes. Your setter is just fetching the existing property value:
this.btn_input.BackColor = buttonColor;
this._buttonColor = buttonColor;
You meant to use value, which is the implicit parameter name for the setter:
this.btn_input.BackColor = value;
this._buttonColor = value;
(Ditto for your if block, but it's hard to tell how that's meant to work as it's not valid C# at the moment.)
As a side note, I'd strongly urge you to start following .NET naming conventions, which include capital letters for properties - so ButtonColor rather than buttonColor.

How to assign triggers to variables in C#?

When coding in Visual Basic, I'm able to define triggers to variables like: Whenever the value of the variable is changed, this triggers a function, which in turn changes the value of another variable. I wonder if there is a way to do the same in C#; that is, I want to define a trigger to a variable, fired every time when the value of that variable is changed.
Below code is how I do it in VB. When running this App, whenever a new user logs in, the App assigns the username like ActiveUserName = "SomeUserName", and this in turn automatically updates the FormMain.StatusLabelUserName.Text in the form. So, is there a way to achieve this trigger in C#?
Public Property ActiveUserName() As String
Get
ActiveUserName = FormMain.StatusLabelUserName.Text
End Get
Set(ByVal Value As String)
FormMain.StatusLabelUserName.Text = Value
End Set
End Property
I believe you're looking for Properties
private int localMember;
public int publicProperty
{
get
{
return localMember;
}
set
{
localMember = value;
//Do whatever you want here.
}
}
The "get" block is run any time you access the value. The "set" block is run any time you assign a value.
This is handled by raising events. This post describes how to do it well.
This is a simple property. Here's the C# syntax:
public string ActiveUserName
{
get { return FormMain.StatusLabelUserName.Text; }
set { FormMain.StatusLabelUserName.Text = value; }
}
Properties can work the same in C#
public string ActiveUserName
{
get{ return FormMain.StatusLabelUserName.Text;}
set{FormMain.StatusLabelUserName.Text = value; /*do more stuff here; */}
}
This can get rather messy and somewhat rigid however. You may consider using events to accomplish the same thing.
Use INotifyPropertyChanged event.
Properties and the set brackets.
INotifyPropertyChanged could be implemented for WPF databindings for exemple.

Categories