In my app, I need a one off timer that'll perform an action and never be used again. I've been cracking down on performance lately and was wondering what the correct way to do this would be.
If I do the following:
NSTimer.CreateScheduledTimer(10, delegate {
Console.WriteLine("Timer fired!");
// other non-trivial code here
});
Once this has fired, is this going to be automagically cleaned up by Mono's GC? Or would it be better to create a reference to this timer (NSTimer timer = NSTimer.CreateScheduledTimer()) and then dispose of it myself?
Does this apply to other objects which can be instantiated in a similar manner?
Your sample code is probably the way to go. GC will clean up sometime after the timer has fired. The only reason you might want to hold a reference to the timer is if you'd want to cancel the timer at some point.
I use this little helper. Good thing is that it can be used in all NSObject derived classes and helps when converting code from ObjC as it is pretty much the same call.
namespace MonoTouch.Foundation.Extensions
{
public static class CoreFoundationExtensions
{
/// <summary>
/// Performs the selector.
/// </summary>
/// <param name='obj'>
/// Object.
/// </param>
/// <param name='action'>
/// Action.
/// </param>
/// <param name='delay'>
/// Delay.
/// </param>
public static void PerformSelector (this NSObject obj, NSAction action, float delay)
{
int d = (int)(1000 * delay);
var thread = new Thread(new ThreadStart ( () => {
using(var pool = new NSAutoreleasePool())
{
Thread.Sleep (d);
action.Invoke ();
}
}));
thread.IsBackground = true;
thread.Start();
}
/// <summary>
/// Performs the selector.
/// </summary>
/// <param name='obj'>
/// Object.
/// </param>
/// <param name='action'>
/// Action.
/// </param>
public static void PerformSelector (this NSObject obj, NSAction action)
{
PerformSelector (obj, action, 0.001f);
}
}
}
Related
I have many elements on my UI. I want to change the entire UI color. Basically like a new "Skin" for my HUD/Menu in game.
What is the best way to do this?
In UIBuilder, I can select a selector class and change the color, and it applies to all elements. How can I do this in runtime?
I have looked into USS variables, but it doesn't look like I can edit those using C# on runtime.
The easiest answer I see is creating a UIManager class and placing it in the scene.
Your UI Manager will have an instance, thus making it a Singleton, here is the code that should be inside your UIManager
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class UIManager : MonoBehaviour
{
public static Singleton Instance { get; private set; }
public Color[] skinColours;
private void Awake()
{
// If there is an instance, and it's not me, delete myself.
if (Instance != null && Instance != this)
{
Destroy(this);
}
else
{
Instance = this;
}
}
public void ReskinUI(int skinIndex)
{
// Repeat this for RawImages, Buttons etc.
foreach (Image image in GameObject.FindObjectsOfType<Image>())
{
image.color = skinColours[skinIndex];
}
}
}
After your define your UIManager, you can use it in your code like this.
UIManager.Instance.ReskinUI(1);
The '1' there, corresponds to the skin index.
Let me know if this helps
Not sure what you are placing on your UI but there are only two generally, raw images and images.
Step 1. Create a script to gather the images and/or raw images and store a link to them
Step 2. Change the colour on those images.
Step 3. Ensure other things can grab your code to change the colour
Step 1:
/// <summary>
/// Gets all the images attached
/// </summary>
private void GetAllImagesInChildren()
{
allGraphics = new List<Graphic>();
foreach (Transform child in transform)
{
var image = child.gameObject.GetComponent<Image>();
if (image)
{
allGraphics.Add(image);
}
else
{
var rawImage = child.gameObject.GetComponent<RawImage>();
if (rawImage)
{
allGraphics.Add(rawImage);
}
}
}
}
Image and Raw image are both 'Graphic' types and they have the color attribute. Next just use GetComponent. It's also good practice to use GetComponent as little as needed hence storing the value. If you are only using RawImages feel free to switch the order.
Step 2:
/// <summary>
/// All raw images and images.
/// </summary>
private List<Graphic> allGraphics;
// Start is called before the first frame update
void Awake()
{
GetAllImagesInChildren();
}
/// <summary>
/// Sets the Color of all the UI elements attached
/// </summary>
/// <param name="newColor">New color</param>
public void SetUIColor(Color newColor)
{
foreach(Graphic graphic in allGraphics)
{
graphic.color = newColor;
}
}
Let's attach the method from step one into a new script, store graphics privately and call it on awake. Then because graphics is now private create a simple public method which just uses our stored values. You could easily overload this with Color32 just copy and paste the method with that.
All together:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIColourChanger : MonoBehaviour
{
/// <summary>
/// All raw images and images.
/// </summary>
private List<Graphic> allGraphics;
// Start is called before the first frame update
void Awake()
{
GetAllImagesInChildren();
}
/// <summary>
/// Sets the Color of all the UI elements attached
/// </summary>
/// <param name="newColor">New color</param>
public void SetUIColor(Color newColor)
{
foreach(Graphic graphic in allGraphics)
{
graphic.color = newColor;
}
}
/// <summary>
/// Gets all the images attached
/// </summary>
private void GetAllImagesInChildren()
{
allGraphics = new List<Graphic>();
foreach (Transform child in transform)
{
var image = child.gameObject.GetComponent<Image>();
if (image)
{
allGraphics.Add(image);
}
else
{
var rawImage = child.gameObject.GetComponent<RawImage>();
if (rawImage)
{
allGraphics.Add(rawImage);
}
}
}
}
}
Then simply the children of the object attached to this script are stored. Then just add:
public UIColourChanger ColorChanger;
or
[SerializeField]
private UIColourChanger colorChanger
To any other script and drag in this one into it to gain access to that public method.
I'm still using OpenRiaServices and I update to version 5.0.0-preview0003.
I tried to add an async method :
[Invoke]
[RequiresAuthentication]
public async Task<string> GetTestAsync()
{
return await Task.FromResult("TEST");
}
But when I'm calling it, the method never returns :
var test = DomainContext.GetTestAsync(CancellationToken.None).Result;
I see that there is no "await" in the generated code :
/// <summary>
/// Asynchronously invokes the 'GetTest' method of the DomainService.
/// </summary>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
/// <returns>An operation instance that can be used to manage the asynchronous request.</returns>
[DebuggerStepThrough()]
public System.Threading.Tasks.Task<InvokeResult<string>> GetTestAsync(CancellationToken cancellationToken = default(CancellationToken))
{
this.ValidateMethod("GetTest", null);
return this.InvokeOperationAsync<string>("GetTest", null, true, cancellationToken);
}
I tried to debug it but I don't know where the problem happens...
Any idea why ?
The issue has been answered over [at the OpenRiaServices Github)(https://github.com/OpenRIAServices/OpenRiaServices/issues/246)
The issue was a deadlock due to calling Task.Result instead of awaiting the result
In unity I keep on getting this error that keeps on bugging me, I tried to remove packages to leave one of these errors and it kept on going on and on, i am developing a game right now using unity engine and the errors are a big pain for me, this is the code that someone asked for, i dont really have much else to write other than this, stackoverlow isnt letting me just post it because its too short
using System;
using System.IO;
using UnityEngine;
namespace UnityEditor.SettingsManagement
{
/// <inheritdoc />
/// <summary>
/// A settings repository that stores data local to a Unity project.
/// </summary>
[Serializable]
public sealed class PackageSettingsRepository : ISettingsRepository
{
const string k_PackageSettingsDirectory = "ProjectSettings/Packages";
const bool k_PrettyPrintJson = true;
bool m_Initialized;
[SerializeField]
string m_Name;
[SerializeField]
string m_Path;
[SerializeField]
SettingsDictionary m_Dictionary = new SettingsDictionary();
/// <summary>
/// Constructor sets the serialized data path.
/// </summary>
/// <param name="package">
/// The package name.
/// </param>
/// <param name="name">
/// A name for this settings file. Settings are saved in `ProjectSettings/Packages/{package}/{name}.json`.
/// </param>
public PackageSettingsRepository(string package, string name)
{
m_Name = name;
m_Path = GetSettingsPath(package, name);
m_Initialized = false;
AssemblyReloadEvents.beforeAssemblyReload += Save;
EditorApplication.quitting += Save;
}
void Init()
{
if (m_Initialized)
return;
m_Initialized = true;
if (File.Exists(path))
{
m_Dictionary = null;
var json = File.ReadAllText(path);
EditorJsonUtility.FromJsonOverwrite(json, this);
if(m_Dictionary == null)
m_Dictionary = new SettingsDictionary();
}
}
/// <value>
/// This repository implementation is relevant to the Project scope.
/// </value>
/// <inheritdoc cref="ISettingsRepository.scope"/>
public SettingsScope scope
{
get { return SettingsScope.Project; }
}
/// <value>
/// The full path to the settings file.
/// This corresponds to `Unity Project/Project Settings/Packages/com.unity.package/name`.
/// </value>
/// <inheritdoc cref="ISettingsRepository.path"/>
public string path
{
get { return m_Path; }
}
/// <summary>
/// The name of this settings file.
/// </summary>
public string name
{
get { return m_Name; }
}
// Cannot call FindFromAssembly from a constructor or field initializer
// static string CreateSettingsPath(Assembly assembly, string name)
// {
// var info = PackageManager.PackageInfo.FindForAssembly(assembly);
// return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, info.name, name);
// }
/// <summary>
/// Get a path for a settings file relative to the calling assembly package directory.
/// </summary>
/// <param name="packageName">The name of the package requesting this setting.</param>
/// <param name="name">An optional name for the settings file. Default is "Settings."</param>
/// <returns>A package-scoped path to the settings file within Project Settings.</returns>
public static string GetSettingsPath(string packageName, string name = "Settings")
{
return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, packageName, name);
}
/// <summary>
/// Save all settings to their serialized state.
/// </summary>
/// <inheritdoc cref="ISettingsRepository.Save"/>
public void Save()
{
Init();
if (!File.Exists(path))
{
var directory = Path.GetDirectoryName(path);
Directory.CreateDirectory(directory);
}
#if UNITY_2019_3_OR_NEWER
if (!AssetDatabase.IsOpenForEdit(path))
{
if (!AssetDatabase.MakeEditable(path))
{
Debug.LogWarning($"Could not save package settings to {path}");
return;
}
}
#endif
try
{
File.WriteAllText(path, EditorJsonUtility.ToJson(this, k_PrettyPrintJson));
}
catch (UnauthorizedAccessException)
{
Debug.LogWarning($"Could not save package settings to {path}");
}
}
/// <summary>
/// Set a value for key of type T.
/// </summary>
/// <param name="key">The settings key.</param>
/// <param name="value">The value to set. Must be serializable.</param>
/// <typeparam name="T">Type of value.</typeparam>
/// <inheritdoc cref="ISettingsRepository.Set{T}"/>
public void Set<T>(string key, T value)
{
Init();
m_Dictionary.Set<T>(key, value);
}
/// <summary>
/// Get a value with key of type T, or return the fallback value if no matching key is found.
/// </summary>
/// <param name="key">The settings key.</param>
/// <param name="fallback">If no key with a value of type T is found, this value is returned.</param>
/// <typeparam name="T">Type of value to search for.</typeparam>
/// <inheritdoc cref="ISettingsRepository.Get{T}"/>
public T Get<T>(string key, T fallback = default(T))
{
Init();
return m_Dictionary.Get<T>(key, fallback);
}
/// <summary>
/// Does the repository contain a setting with key and type.
/// </summary>
/// <param name="key">The settings key.</param>
/// <typeparam name="T">The type of value to search for.</typeparam>
/// <returns>True if a setting matching both key and type is found, false if no entry is found.</returns>
/// <inheritdoc cref="ISettingsRepository.ContainsKey{T}"/>
public bool ContainsKey<T>(string key)
{
Init();
return m_Dictionary.ContainsKey<T>(key);
}
/// <summary>
/// Remove a key value pair from the settings repository.
/// </summary>
/// <param name="key"></param>
/// <typeparam name="T"></typeparam>
/// <inheritdoc cref="ISettingsRepository.Remove{T}"/>
public void Remove<T>(string key)
{
Init();
m_Dictionary.Remove<T>(key);
By the definition of 'RequestScriptReload' :
"The Unity Editor reloads script assemblies asynchronously on the next frame. This resets the state of all the scripts, but Unity does not compile any code that has changed since the previous compilation."
That means that your problem is probably with something that you changed.
You can try:
Going back to the last time everything wored and go on from there.
Closing all of you unity and scripting applications and opening it again.
How can I be notified when ProgressBar's Value changes with .NET UIAutomation framework? I dont see such property in AutomationElement class.
I drew this sample directly from the MSDN documentation, changing only the property:
AutomationPropertyChangedEventHandler propChangeHandler;
/// <summary>
/// Adds a handler for property-changed event; in particular, a change in the value
/// </summary>
/// <param name="element">The UI Automation element whose state is being monitored.</param>
public void SubscribePropertyChange(AutomationElement element)
{
Automation.AddAutomationPropertyChangedEventHandler(element,
TreeScope.Element,
propChangeHandler = new AutomationPropertyChangedEventHandler(OnPropertyChange),
ValuePattern.ValueProperty);
}
/// <summary>
/// Handler for property changes.
/// </summary>
/// <param name="src">The source whose properties changed.</param>
/// <param name="e">Event arguments.</param>
private void OnPropertyChange(object src, AutomationPropertyChangedEventArgs e)
{
AutomationElement sourceElement = src as AutomationElement;
if (e.Property == ValuePattern.ValueProperty)
{
// TODO: Do something with the new value.
// The element that raised the event can be identified by its runtime ID property.
}
else
{
// TODO: Handle other property-changed events.
}
}
public void UnsubscribePropertyChange(AutomationElement element)
{
if (propChangeHandler != null)
{
Automation.RemoveAutomationPropertyChangedEventHandler(element, propChangeHandler);
}
}
I am writing a plugin where I check if a particular value of a field, an Option Set is equal to a specific value and if so, then I do certain actions.
Now, within the plugin C# code, how can I check that the Option Set field is not null - i.e., is set to the Default Value?
What I did (clearly, that is wrong) because, it never went past the Null check statement. And, if I did not have the check, then I get this error message
Error:
Unexpected exception from plug-in (Execute): CRM.AppStateHandler.Plugins.PostApplicationCreate: System.NullReferenceException: Object reference not set to an instance of an object.
Code:
application applicationEntity = entity.ToEntity<new_application>();
if (new_applicationEntity.new_Applicationstatus != null)
{
var applicationStatus = applicationEntity.new_Applicationstatus.Value;
if (applicationStatus == CRMConstants.EntityApplication.Attributes.ApplicationStatusOptions.Applying)
{
//my logic
}
}
File constants.cs has the following
class CRMConstants
{
public struct EntityApplication
{
public struct Attributes
{
public struct ApplicationStatusOptions
{
// More before this
public const int Applying = 100000006;
// More to come
}
}
}
I think SergeyS has your fix, but I'll add some other (hopefully) helpful comments.
Don't custom create structs for your Option Set Values. Use the CrmSrvcUtil to create enums for you automatically.
I get annoyed with having to check for OptionSetValues being null or not, so I use these extension methods to make my life easier:
/// <summary>
/// Returns the value of the OptionSetValue, or int.MinValue if it is null
/// </summary>
/// <param name="osv"></param>
/// <param name="value"></param>
/// <returns></returns>
public static int GetValueOrDefault(this OptionSetValue osv)
{
return GetValueOrDefault(osv, int.MinValue);
}
/// <summary>
/// Returns the value of the OptionSetValue, or int.MinValue if it is null
/// </summary>
/// <param name="osv"></param>
/// <param name="value"></param>
/// <returns></returns>
public static int GetValueOrDefault(this OptionSetValue osv, int defaultValue)
{
if (osv == null)
{
return defaultValue;
}
else
{
return osv.Value;
}
}
/// <summary>
/// Allows for Null safe Equals Comparison for more concise code. ie.
/// if(contact.GenderCode.NullSafeEquals(1))
/// vs.
/// if(contact.GenderCode != null && contact.gendercode.Value == 1)
/// </summary>
/// <param name="osv"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool NullSafeEquals(this OptionSetValue osv, int value)
{
if (osv == null)
{
return false;
}
else
{
return osv.Value == value;
}
}
/// <summary>
/// Allows for Null safe Equals Comparison for more concise code. ie.
/// if(contact.GenderCode.NullSafeEquals(new OptionSet(1)))
/// vs.
/// if(contact.GenderCode != null && contact.gendercode.Value == new OptionSet(1))
/// </summary>
/// <param name="osv"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool NullSafeEquals(this OptionSetValue osv, OptionSetValue value)
{
if (osv == null)
{
return osv == value;
}
else
{
return osv.Equals(value);
}
}
There are two methods each with an overload:
GetValueOrDefault - This is equivalent to the Nullable.GetValueOrDefault(). The one difference is rather than defaulting to 0, I default to int.MinValue to make sure I don't accidentally match on a 0 optionset value. The Overload allows you to specify the default value if you'd like.
NullSafeEquals - This is the one you'd be using in your code to not have to check for null
application applicationEntity = entity.ToEntity<new_application>();
if (applicationEntity.new_Applicationstatus.NullSafeEquals(CRMConstants.EntityApplication.Attributes.ApplicationStatusOptions.Applying))
{
//my logic
}
You are checking:
if (new_applicationEntity.new_Applicationstatus != null)
but you need to check:
if (applicationEntity.new_Applicationstatus != null)