Select value from string - c#

I have this code that is telling a system to open the tab "Employee" in a WPF client.
class Startup
{
public void Init()
{
var screen = Tabs.Employee;
Tabs.OpenTab(screen, null);
}
}
What I would like to do is something like this:
string screenName = "Employee";
var screen = Tabs.screenName;
In order to be able to pass the Employee as a value.
The Tabs class looks like this:
public class Tabs
{
public delegate void AddDockTab(string controlName, object argument = null);
public const string Empty = "Empty";
public const string Employee = "Employee";
public const string Customer = "Customer";
private static UnicontaTabs utab;
public static event AddDockTab OnAddDockTab;
protected Tabs()
{
utab = this;
}
public static void OpenTab(string controlName, object argument)
{
if (utab != null)
{
utab.AddTab(controlName, argument);
}
}
protected virtual void AddTab(string controlName, object argument)
{
Tabs.OnAddDockTab?.Invoke(controlName, argument);
}
public static IEnumerable<string> GetControlNames()
{
FieldInfo[] fields = typeof(Tabs).GetFields(BindingFlags.Static | BindingFlags.Public);
return fields.Select((FieldInfo f) => f.Name);
}
}

Related

Newtonsoft.Json.JsonConvert(object) returns null object

I have a 'complex' object that I want to serialize with JSon.Convert. As 'complex' objects go it is rather simple: Here are the objects:
The main object:
public class CustomerContactRequest
{
private RequestHeaderArea header;
private RequestPayloadArea payload;
public CustomerContactRequest(string headerMessage, string npsGroup, string npsSection)
{
this.header = new RequestHeaderArea(headerMessage);
this.payload = new RequestPayloadArea(npsGroup, npsSection);
}
}
The 'header' Object:
public class RequestHeaderArea
{
private string headerMessage;
public string HeaderMessage { get { return headerMessage; } }
public RequestHeaderArea(string headerMessage)
{
this.headerMessage = headerMessage;
}
}
The Payload Area:
public class RequestPayloadArea
{
private string npsGroup;
private string npsSection;
public string NPSGroup { get { return npsGroup; } }
public string NPSSection { get { return npsSection; } }
public RequestPayloadArea(string npsGroup, string npsSection)
{
this.npsGroup = npsGroup;
this.npsSection = npsSection;
}
}
And Finally, the main process:
static void Main(string[] args)
{
CustomerContactRequest ccRequest = new CustomerContactRequest(
headerMessage: "test",
npsGroup: "1234567",
npsSection: "0000");
retrieveContactInfo(ccRequest);
}
static void retrieveContactInfo(CustomerContactRequest ccRequest)
{
string jsonRequest = JsonConvert.SerializeObject(ccRequest);
// code to call service
}
jsonRequest returns {} even though ccRequest contains the expected values. What am I missing?
I am expecting something like this (sans formatting):
{
"headerArea": {
"messageId": "test"
},
"payloadArea": {
"group": {
"Number": "1234567",
"Suffix": "0000"
}
}
}
Implementing Chris's answer my classes now look like below (main program did not change except that I added Formatted.Indented to the SerializeObject call to make it pretty):
CustomerContactRequest:
public class CustomerContactRequest
{
public RequestHeaderArea headerArea;
public RequestPayloadArea payloadArea;
public CustomerContactRequest(string headerMessage, string npsGroup, string npsSection)
{
this.headerArea = new RequestHeaderArea(headerMessage);
this.payloadArea = new RequestPayloadArea(npsGroup, npsSection);
}
}
RequestHeaderArea:
public class RequestHeaderArea
{
private string messageId;
public string MessageId { get { return messageId; } }
public RequestHeaderArea(string headerMessage)
{
this.messageId = headerMessage;
}
}
RequestPayloadArea:
public class RequestPayloadArea
{
public Group group;
public RequestPayloadArea(string npsGroup, string npsSection)
{
this.group = new Group(npsGroup, npsSection);
}
}
And a new class: Group:
public class Group
{
public string Number;
public string Suffix;
public Group(string npsGroup, string npsSection)
{
Number = npsGroup;
Suffix = npsSection;
}
}
Now my Json looks exactly as expected (see green text above)
SerializeObject ignores private members by default. You can either make them public, or by adding the SerializableAttribute to your CustomerContractRequest class.

Is there an event for when all properties of an object have been set?

Imagine a simple POCO
public class Test{
public int ID {get; set;}
public string Name {get; set;}
public string SomeProperty {get; set;}
}
Is there a way to wire this object up such that an event will fire only when all properties have been set? Like an InitializeComplete event or something? Or alternately is there a way to easily create such an event custom?
thanks
You could implement this by yourself like so:
public delegate void AllPropertiesSetDelegate();
public class Test
{
public delegate void AllPropertiesSetDelegate(object sender, EventArgs args);
public int Id
{
get => _id;
set
{
_id = value;
CheckAllProperties();
}
}
private int _id;
public string Name
{
get => _name;
set
{
_name = value;
CheckAllProperties();
}
}
private string _name;
private void CheckAllProperties()
{
//Comparing Id to null is pointless here because it is not nullable.
if (Name != null && Id != null)
{
AllPropertiesSet?.Invoke(this, new EventArgs());
}
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.AllPropertiesSet += delegate { AllPropsSet(); };
t.Id = 1;
t.Name = "asd";
Console.ReadKey();
}
static void AllPropsSet()
{
Console.WriteLine("All properties have been set.");
}
}
See for yourself if you can get the implementation smaller/less painfull to deal with.
Test code:
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.AllPropertiesSet += delegate { AllPropsSet(); };
t.Id = 1;
t.Name = "asd";
Console.ReadKey();
}
static void AllPropsSet()
{
Console.WriteLine("All properties have been set.");
}
}
Heres how you could use reflection to check all non-value types for null:
public static bool AllPropertiesNotNull<T>(this T obj) where T : class
{
foreach (var prop in obj.GetType().GetProperties())
{
//See if our property is not a value type (value types can't be null)
if (!prop.PropertyType.IsValueType)
{
if (prop.GetValue(obj, null) == null)
{
return false;
}
}
}
return true;
}
You can consume this in the original code by modifying the CheckAllProperties method:
private void CheckAllProperties()
{
if (this.AllPropertiesNotNull())
{
AllPropertiesSet?.Invoke(this, new EventArgs());
}
}
If you want to ensure that an object is properly created, why not make it so the only way to create it is to also set all the properties.
public class Test{
public int ID {get; set;}
public string Name {get; set;}
public string SomeProperty {get; set;}
// Constructor
public Test(int id, string Name, string someProperty)
{
this.ID = id;
this.Name = name;
this.SomeProperty = someProperty;
}
}
Here's a variation on #fstam's answer. It changes this to a full on event and makes the call to check the properties cleaner. If you upvote me, upvote #fstam.
First the class:
public class TestPropertyCheck
{
public event EventHandler AllPropertiesSet;
public int Id
{
get => _id;
set
{
_id = value;
CheckAllProperties(PropertyNames.Id);
}
}
private int _id;
public string Name
{
get => _name;
set
{
_name = value;
CheckAllProperties(PropertyNames.Name);
}
}
private string _name;
public string Address
{
get => _address;
set
{
_address = value;
CheckAllProperties(PropertyNames.Address);
}
}
private string _address;
private void CheckAllProperties(PropertyNames propName)
{
propertiesSet |= propName;
if (propertiesSet == PropertyNames.AllProps)
{
AllPropertiesSet?.Invoke(this, new EventArgs());
}
}
private PropertyNames propertiesSet = PropertyNames.None;
[Flags]
private enum PropertyNames
{
None = 0,
Id = 0x01,
Name = 0x02,
Address = 0x04,
AllProps = Id | Name | Address,
}
}
Then a test program
public static class PropertyCheckTester
{
public static void Test()
{
var test = new TestPropertyCheck();
test.AllPropertiesSet += AllPropertiesSet;
Debug.WriteLine("Setting Name");
test.Name = "My Name";
Debug.WriteLine("Setting ID");
test.Id = 42;
Debug.WriteLine("Setting Address");
test.Address = "Your address goes here";
}
public static void AllPropertiesSet(object sender, EventArgs args)
{
Debug.WriteLine("All Properties Set");
}
}
And the output:
Setting Name
Setting ID
Setting Address
All Properties Set
Such event is fairly easy to implement for normal classes with full properties (code below is from answer of #fstam and partially from head, tell me if something is wrong, or threat it as pseudo-code):
public class Test
{
public EventHandler InitializeCompleted;
int _id;
public int Id
{
get => _id;
set
{
_id = value;
CheckAllProperties();
}
}
string _name;
public string Name
{
get => _name;
set
{
_name = value;
CheckAllProperties();
}
}
HashSet<string> _initialized = new HashSet<string();
void CheckAllProperties([CallerMemberName] string property = null)
{
if(_initialized == null) // ignore calls after initialization is done
return;
_initialized.Add(property);
if(_initialized.Count == 2) // all properties setters were called
{
_initialized = null;
InitializeCompleted?.Invoke(this, EventArgs.Empty);
}
}
}
Using reflection can make the task even simpler: you can get property counter (no need to maintain that number in CheckAllProperties), mark properties which has to be included/excluded. If you decide to do so, don't forget to use lazy pattern, to only do it once for type, not for each instance.

Why textbox doesn't print the text, but I got string ?

I am using Windows Form;
I want to set TextBox tbCommandName1.Text which is on my Form;
I got the value from GetInfo() and how can I send string from Second.GetInfo() to my main Form like to class Favorit ?
I don't want to create an instance of Form; Because it makes to Initialize all my components again.
I bet I have to use get/set.
Give me please, a few hints;
THanks a lot to you, my guru!
namespace ParserFavorit
{
public partial class Favorit : Form, IForm
{
public Favorit()
{
InitializeComponent();
}
public string CommandName1
{
get { return tbCommandName1.Text; }
set { tbCommandName1.Text = value; }
}
private void bStart_Click(object sender, EventArgs e)
{
string ID = tbGetID.Text;
Second.StartBrowser(Second.GetDriver(), ID);
}
}
public class Second : Form
{
private static ChromeDriver driver = null;
public static ChromeDriver GetDriver()
{
if (driver == null)
{
driver = new ChromeDriver();
}
return driver;
}
public static void StartBrowser(ChromeDriver driver, string IDevent)
{
driver.Navigate().GoToUrl("myURL" + IDevent);
GetInfo();
}
public static void GetInfo()
{
System.Threading.Thread.Sleep(2000);
string CommandName1 = driver.FindElement(By.XPath(".//*[#id='react-root']/div/div[2]/div/div[1]/div/div[1]/div/div[1]/div/header/div[2]/span[1]")).Text;
string CommandName2 = driver.FindElement(By.XPath(".//*[#id='react-root']/div/div[2]/div/div[1]/div/div[1]/div/div[1]/div/header/div[2]/span[2]")).GetAttribute("innerHTML");
}
}
interface IForm
{
string CommandName1 { get; set; }
}
}
I am sure that I have a TextBox with name tbCommandName1;
My form doesn't show the value which I got from website, but method PrintName got it.
How so?
namespace ParserFavorit
{
public partial class Favorit : Form
{
public Favorit()
{
InitializeComponent();
}
private void bStart_Click(object sender, EventArgs e)
{
string ID = tbGetID.Text;
Second.StartBrowser(Second.GetDriver(), ID);
}
public void PrintName(string Command1Name)
{
string Name = Command1Name;
tbCommandName1.Text = Name;
}
}
public class Second
{
private static ChromeDriver driver = null;
public static ChromeDriver GetDriver()
{
if (driver == null)
{
driver = new ChromeDriver();
}
return driver;
}
public static void StartBrowser(ChromeDriver driver, string ID)
{
driver.Navigate().GoToUrl("https://m.favorit.com.ua/uk/live/events/" + ID);
GetInfo();
}
public static void GetInfo()
{
System.Threading.Thread.Sleep(2000);
string CommandName1 = driver.FindElement(By.XPath(".//*[#id='react-root']/div/div[2]/div/div[1]/div/div[1]/div/div[1]/div/header/div[2]/span[1]")).Text;
Favorit favorit = new Favorit();
favorit.PrintName(CommandName1);
}
}
}

delegate method returns a null value

For the past two hours I've been trying to experiment with delegates / events - my aim is to inform users with both the previous book name and new book as a new book name is set.
However, in all cases in my Abstract class, NameChanged(args.ExistingName, args.NewNames); returns null. I can't seem to figure out why, I have tried manually passing through two string params yet visual studio throws an error stating that NameChanged contains a null value.
internal interface Iinterface
{
void AddContact(string name, string number);
void RemoveContact(string name);
void RetrieveContacts();
void RetrieveByName(string name);
void RetrieveByNumber(string number);
string Name { get; set; }
}
public abstract class Abstract : Iinterface
{
public abstract void AddContact(string name, string number);
public abstract void RemoveContact(string name);
public abstract void RetrieveContacts();
public abstract void RetrieveByName(string name);
public abstract void RetrieveByNumber(string number);
public string Name{
get
{
return _name;
}
set
{
NameChangedEventArgs args = new NameChangedEventArgs();
args.ExistingName = _name;
args.NewName = value;
NameChanged(args.ExistingName, args.NewName); // this refers to the abstract class?
_name = value;
}
}
public NameChangedEventHandler NameChanged; // I presume here we're taking an instance of the delegate method.
protected string _name;
}
public class PhoneBook : Abstract
{
public PhoneBook()
{
_name = "phone book name";
}
public override void AddContact(string name, string number)
{
contacts.Add(name, number);
}
public override void RemoveContact(string name)
{
contacts.Remove(name);
}
public override void RetrieveContacts()
{
foreach (KeyValuePair<string, string> entry in contacts)
{
Console.WriteLine("Name : {0} Number : {1}", entry.Key, entry.Value);
}
}
public override void RetrieveByName(string name)
{
foreach(KeyValuePair<string, string> entry in contacts)
{
if(entry.Key == name)
{
Console.WriteLine("Name : {0} Number : {1}", entry.Key, entry.Value);
}
}
}
public override void RetrieveByNumber(string number)
{
foreach(KeyValuePair<String,string> entry in contacts)
{
if (entry.Value == number)
{
Console.WriteLine("Name : {0} Number : {1}", entry.Key, entry.Value);
}
}
}
Dictionary<string, string> contacts = new Dictionary<string, string>();
}
public class NameChangedEventArgs : EventArgs
{
public string ExistingName { get; set; }
public string NewName { get; set; }
}
{
// public delegate void NameChangedEventHandler(object sender, NameChangedEventArgs args);
public delegate void NameChangedEventHandler(string existingName, string newName);
}
class Program
{
static void Main(string[] args)
{
PhoneBook book = new PhoneBook();
setName(book);
addContact(book);
retrieveByName(book);
retrieveByNumber(book);
book.NameChanged = new NameChangedEventHandler(OnNameChanged); // call OnNameChanged whenever someone invokes this delegate
Console.ReadLine();
/* book.retrieveContacts(); */
}
private static void setName(PhoneBook book)
{
book.Name = "book name";
Console.WriteLine(book.Name);
}
private static void retrieveByNumber(PhoneBook book)
{
book.RetrieveByNumber("0323242389");
}
private static void retrieveByName(PhoneBook book)
{
book.RetrieveByName("james");
}
private static void addContact(PhoneBook book)
{
book.AddContact("james", "0151289");
book.AddContact("Bob", "0323242389");
book.AddContact("Hannah", "34234");
}
static void OnNameChanged(string existingName, string newName)
{
Console.WriteLine($"Gradebook changing name from {existingName} to {newName}");
}
}
For registering a delegate or event with a method, the following is the syntax for it:
book.NameChanged+= new NameChangedEventHandler(OnNameChanged);
and Secondly you should not be invoking it blindly at invoking side.
you should be checking if someone has subscribed to it or any method is assigned to it like:
if(NameChanged !=null)
NameChanged(args.ExistingName, args.NewName);
or in c# 6:
NameChanged?.Invoke(args.ExistingName, args.NewName);
Hope it helps you.

Func list for storing function pointer and parameter value

I want to store a list of functions with their parameter value and later when I am done adding function to the list. I want to execute all in the order I have added.
For example, I want to use func instead of action and don't want to create anonymous functions while calling parametered function:
Dynamic function list class to hold a function list and execute it later.
class DynamicFunctionList
{
public List<Action> DynamicList = new List<Action>();
public void Execute()
{
foreach (var obj in DynamicList)
{
obj();
}
}
}
some class with functions
public class SomeClass
{
public void PrintHello()
{
Console.Write("Hello");
}
public void PrintBye()
{
Console.Write("Print Bye");
}
public int GetPrinterValue()
{
return 2;
}
public int Add(int a, int b)
{
return (a + b);
}
}
And this is how you will use it
public static void MainClass()
{
var first = 0;
var second = 0;
var dfList = new DynamicFunctionList();
var sClass = new SomeClass();
dfList.DynamicList.Add(() => first = sClass.GetPrinterValue()); // problem line
dfList.DynamicList.Add(sClass.PrintBye);
dfList.DynamicList.Add(sClass.PrintHello);
dfList.DynamicList.Add(() => second = sClass.Add(2, 3)); // problem
dfList.Execute();
}
I do something like that:
public void main()
{
List<MethodInvoker> methods = new List<MethodInvoker>();
methods.Add(new MethodInvoker(SomeMethod));
foreach (var method in methods)
{
method.Invoke();
}
}
public void SomeMethod()
{
//... do something
}
EDIT 1:
You can use MethodBase.Invoke from System.Reflection namespace (more infos: https://msdn.microsoft.com/en-us/library/a89hcwhh%28v=vs.110%29.aspx)
You can do something like that:
public class DynamicMethod
{
public string ClassName { get; set; }
public string MethodName { get; set; }
public object[] Parameters { get; set; }
public static object InvokeMethod(DynamicMethod methodInfo)
{
var magicType = Type.GetType(methodInfo.ClassName);
var magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
var magicInstance = magicConstructor.Invoke(new object[] {});
var magicMethod = magicType.GetMethod(methodInfo.MethodName);
return magicMethod.Invoke(magicInstance, methodInfo.Parameters);
}
}
public class Example
{
public static void main()
{
var d1 = new DynamicMethod
{
ClassName = "SomeClass",
MethodName = "Add",
Parameters = new object[] { 1, 2 }
};
var returnedValue = DynamicMethod.InvokeMethod(d1);
Console.WriteLine(returnedValue.ToString());
}
Also you can add more information to this class, like some way to store the returned type to do the properly cast.

Categories