stupid question,but still. I have some variable, let it be MyVariable, which gets its value in one of the methods in code-behind, in MouseClick, for example, but then value of MyVariableis used in a method in another class(I'm using different Patterns). Of course, in this class MyVariable is invisible, but what is better to do?
public partial class MainWindow : Window
{
Hero Hero1 = new Hero();
Notify newNotify = new Notify();
public MainWindow()
{
InitializeComponent();
Collections coll = new Collections();
}
private void weapons_DragLeave(object sender, DragEventArgs e)
{
Hero1.Attack = ((Weapon) listweapons.SelectedItem)._attack;
newNotify.ThrowHero().Attack = Hero1.Attack;
newNotify.Dropped += Show_Message;
newNotify.DroppedEquipment();
TextBox2.Text = newNotify.ThrowHero().Description;//this gets its value from attack
}
public void Show_Message()
{
Console.WriteLine(newNotify.ThrowHero().Description =
"Защита:" + newNotify.ThrowHero().Protection + "атака:" + newNotify.ThrowHero().Attack);
}
}
and then i have another method in another class
public class SavingInWord : IWordSaving
{
public void ExportToWord()
{
var wordApp = new Word.Application();
wordApp.Visible = false;
Word.Document doc = wordApp.Documents.Add();
doc.Select();
wordApp.Selection.TypeText("Description:" + newNotify.ThrowHero().Description); //newNotify.ThrowHero().Description) can't be seen here, but i need to have the value here which i got from weapons_DragLeave method
doc.SaveAs(#"D:...doc");
wordApp.Visible = true;
}
}
in another class:
public class Notify
{
Hero hero1 = new Hero();
public Hero ThrowHero()
{
return hero1;
}
public delegate void MyEventhandler();
public event MyEventhandler Dropped;
public void DroppedEquipment()
{
if (Dropped != null)
Dropped();
}
}
In your root-most namespace
public static class Globals
{
Notify newNotify = new Notify();
}
Then you'll be able to access it from where ever.
Related
I have a problem with using nancyfx in my winform application (I make a winform app and use a nancyfx inside the application) So i can use some API url to make change in the winform without additional server or services (because i attached the nancy in the winform apps)
Here is my Form1.cs
public partial class Form1 : Form
{
public Form1(bool test)
{
InitializeComponent();
textBox1.Text += "Apps Method "+ Environment.NewLine;
}
public bool startTestAPI()
{
textBox1.Text += "Api Worked" + Environment.NewLine);
}
private void button2_Click(object sender, EventArgs e)
{
HostingAPI s = new HostingAPI();
s.Start();
textBox1.Text += "Api Running" + Environment.NewLine);
}
}
public class ModuleCDM : NancyModule
{
public ModuleCDM()
{
try
{
Thread th2 = Thread.CurrentThread;
Get["/Start"] = parameters =>
{
Form1 form = new Form1(false);
Thread testthread = Form1.curthread;
bool res = form.startTestAPI();
if (res == true)
{
var feeds = new string[] { "Success" };
return Response.AsJson(feeds);
}
else
{
var feeds = new string[] { "Failed" };
return Response.AsJson(feeds);
}
};
}
}
}
and this is my HostingAPI.cs
public class HostingAPI
{
private NancyHost hostNancy;
private string hostUrl;
public void Start()
{
hostUrl = ConfigModule.ModuleAddress;
if (hostUrl == null) hostUrl = "http://localhost:5005";
hostNancy = new NancyHost(new Uri(hostUrl));
hostNancy.Start();
}
public void Stop()
{
hostNancy.Stop();
}
}
And it successfully run without error, but when i call api (localhost:5005/Start) the textbox in winform apps not add the text i wanted ("Api Worked"). I noticed it is because Nancyfx create another thread when there is API call, and i can use invoke/begininvoke because !invokerequired always comes with value false. So how can i access the main thread or maybe another solution to update the UI when i call the API.
Thanks
You have 2 issues in here.
You start host api service from Form1 instance then within Nancy Module you create a different Form1 instance which is invisible and you try to do access certain methods within that class
Cross thread issue as you rightfully guessed . You are trying to write from another thread context than the UI thread
Look at the code at below to achieve this. Bear in mind that you can create Singleton Form or find another way to access the instance of Form1
public class HostingAPI
{
private NancyHost hostNancy;
private string hostUrl;
public HostingAPI()
{
}
public void Start()
{
var hostConfig = new HostConfiguration
{
UrlReservations = new UrlReservations
{
CreateAutomatically = true
},
};
//hostUrl = ConfigModule.ModuleAddress;
if (hostUrl == null) hostUrl = "http://localhost:5005";
hostNancy = new NancyHost(hostConfig,new Uri(hostUrl));
hostNancy.Start();
}
public void Stop()
{
hostNancy.Stop();
}
}
public partial class Form1 : Form
{
delegate void SetTextCallback(string text);
public static Form1 Instance;
public Form1(bool test)
{
InitializeComponent();
textBox1.Text += "Apps Method " + Environment.NewLine;
Instance = this;
}
private void button1_Click(object sender, EventArgs e)
{
HostingAPI s = new HostingAPI();
s.Start();
textBox1.Text += "Api Running" + Environment.NewLine;
}
public void startTestAPI()
{
SetText("Api Worked" + Environment.NewLine);
}
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text += text;
}
}
}
public class ModuleCDM : NancyModule
{
public ModuleCDM()
{
try
{
Thread th2 = Thread.CurrentThread;
Get["/Start"] = parameters =>
{
var form1 = Form1.Instance;
form1.startTestAPI();
var feeds = new[] {"Success"};
return Response.AsJson(feeds);
};
}
catch
{
}
}
}
I'm having issues passing strings from my main form to another form named unlockForm.
In my mainForm I create each string like so
public string race
{
get;set;
}
I've been trying to access them from the unlockForm, but creating a new mainForm like this
mainForm mainScreen = new mainForm();
unlockRace = mainform.race;
gives me a StackOverflowException was unhandled error on the first line.
I haven't had this problem when making new forms in the Main Form, so I'm wondering what the correct way to do this is.
Edit:
Here is the entire code as requested by #deathismyfriend
This is the mainForm Constructor
public mainForm()
{
InitializeComponent();
}
This is the code in the mainForm that updates the race string.
public string race
{
get;set;
}
private void raceUpdate(object sender, EventArgs e)
{
if (raceBox.Text == "Human")
{
if (infoText != humanText)
{
infoText = humanText;
infoboxUpdate(sender, e);
}
}
else if (raceBox.Text == "Troll")
{
if (infoText != trollText)
{
infoText = trollText;
infoboxUpdate(sender, e);
}
}
race = raceBox.Text;
if (race == "")
{
race = "Unspecified";
}
}
Here is the code in my unlockForm
public unlockForm()
{
InitializeComponent();
getStats();
}
mainForm mainScreen = new mainForm();
private void getStats()
{
race = mainScreen.race;
}
Edit #2:
Even when I make my code for unlockForm the following
public unlockForm()
{
InitializeComponent();
//getStats();
}
mainForm mainScreen = new mainForm();
I still receive the error
There are two ways
1:
In UnlockForm.cs
private string _race;
public UnlockForm(string race)
{
_race = race;
}
In MainForm.cs
private void LuanchUnlockForm()
{
var unlockForm = new UnlockForm("Human");
unlockForm.ShowDialog();
}
2nd way:
In UnlockForm.cs
private MainForm _mainForm;
public UnlockForm(MainForm mainForm)
{
_mainForm= mainForm;
}
private void GetRace()
{
var myRace = _mainForm.race;
}
In MainForm.cs
private void LuanchUnlockForm()
{
var unlockForm = new UnlockForm(this);
unlockForm.ShowDialog();
}
If you want to send multiple string do the following
Create new class just like as
Human.cs
public class Human
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
// or anything you want
}
now
In UnlockForm.cs
private Human _human;
public UnlockForm(Human human)
{
_human= human;
}
private void GetHumanAttributes()
{
var age = _human.Age;
//and others ...
}
In MainForm.cs
private void LuanchUnlockForm()
{
var human = new Human();
human.Name = "name";
human.Age = 19;
// others
var unlockForm = new UnlockForm(human);
unlockForm.ShowDialog();
}
I have my progressbar in form1. and i have another class called process.cs
In the main form I have these two functions...
public void SetProgressMax(int max)
{
uiProgressBar.Value = 0;
uiProgressBar.Minimum = 0;
uiProgressBar.Maximum = max;
}
public void IncrementProgress()
{
uiProgressBar.Increment(1);
}
How can I call these functions from my process.cs class?
You're creating a "tightly coupled" solution which requires the process class to have a reference to the Form (I'll use Form1 in this example).
So in your process class, you need to create a variable to store the reference to the form, and allow a way to pass that reference in. One way is to use the constructor of the class:
public class process
{
private Form1 f1 = null;
public process(Form1 f1)
{
this.f1 = f1;
}
public void Foo()
{
if (f1 != null && !f1.IsDisposed)
{
f1.SetProgressMax(10);
f1.IncrementProgress();
f1.IncrementProgress();
f1.IncrementProgress();
}
}
}
Here's an example of creating the process class from within Form1 and passing the reference in:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
process p = new process(this);
p.Foo();
}
public void SetProgressMax(int max)
{
uiProgressBar.Value = 0;
uiProgressBar.Minimum = 0;
uiProgressBar.Maximum = max;
}
public void IncrementProgress()
{
uiProgressBar.Increment(1);
}
}
--- EDIT ---
Here's a boiled down version of the "loosely coupled" events approach (ignoring multi-threading issues for simplicity):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
process p = new process();
p.Progress += p_Progress;
p.Foo();
}
void p_Progress(int value)
{
uiProgressBar.Value = value;
}
}
public class process
{
public delegate void dlgProgress(int value);
public event dlgProgress Progress;
public void Foo()
{
// ... some code ...
// calcuate the current progress position somehow:
int i = (int)((double)3 / (double)10 * (double)100); // 30% complete
// raise the event if there are subscribers:
if (Progress != null)
{
Progress(i);
}
}
}
Note that in this approach the process class has no reference to the form and has no idea what is being done with the progress value. It simply reports the progress and the subscriber (the form in this case) decides what to do with that information.
I am trying to raise an event in a DLL file refrenced to a windows forms project.
I have the following message when I run the program "Object is not set to an instace of an object":
namespace Server
{
public delegate void messageHnadler();
public class ClassServer
{
public event messageHnadler messageForChat
public string Message { get; set; }
public Socket listenerSocket;
public BinaryFormatter transBinary;
public Thread threadingServer;
public TcpListener listenerServer;
private List<TcpClient> connectedClients = new List<TcpClient>();
public bool OpenServer(string ipAddress, int PortNumber)
{
try
{
listenerServer = new TcpListener(IPAddress.Parse(ipAddress), PortNumber);//creating listener for clients to connect
listenerServer.Start();
threadingServer = new Thread(LoopThroughClients);
threadingServer.Start();
threadingServer = new Thread(GetMessage);
threadingServer.Start();
return true;
}
catch (Exception)
{
return false;
}
}
public void LoopThroughClients()
{
listenerSocket = listenerServer.AcceptSocket();
}
public void GetMessage()
{
while (true)
{
if (listenerSocket != null)
{
NetworkStream streamWithClient = new NetworkStream(listenerSocket);
transBinary = new BinaryFormatter();
string stringFromClient = (string)transBinary.Deserialize(streamWithClient);
if (stringFromClient != null)
{
Message = stringFromClient;
messageForChat();
}
streamWithClient = new NetworkStream(listenerSocket);
BinaryFormatter tranBinary = new BinaryFormatter();
tranBinary.Serialize(streamWithClient, stringFromClient);
stringFromClient = null;
}
}
}
In the windows forms project I signed the event to a function:
namespace Chat_Project_Server_UI
{
public partial class SeverUI : Form
{
OpenServerForm openServer = new OpenServerForm();
ClassServer serverForEvent = new ClassServer();
public SeverUI()
{
InitializeComponent();
openServer.ShowDialog();
serverForEvent.messageForChat += new messageHnadler(serverForEvent_messageForChat);
OpenningServer();
}
public void OpenningServer()
{
if(openServer.IsConnected)
{
ChatTextBox.AppendText("SERVER OPEN!\n");
}
else
{
ChatTextBox.AppendText("Faild to open server...\n");
}
}
private void test_Click(object sender, EventArgs e)
{
ChatTextBox.AppendText("aaaaa");
}
public void EventHolder()
{
}
void serverForEvent_messageForChat()
{
ChatTextBox.AppendText(serverForEvent.Message);
}
}
Always check if a handler has been assigned first as follows:
var handler = messageForChat;
if (handler != null)
handler()
Standard Way to handle Events inside the Class that defines it Is to Create A Method Named OnXxx and Always Check whether the Event is Assigned Handler Or Not
in your case define new function as following:
protected void OnMessageForChat(){
//protected modifier allows subclasses to raise the event by calling this method
if (messageForChat!=null)messageForChat();
}
And WhenEver you want to raise the event Just Call this Function
I have the following code:
namespace SSS.RemoteTruckService
{
public partial class Startup : Form
{
private Timer _gpsTimer;
private Timer _ppsTimer;
private Timer _creditCardTimer;
private Timer _iniTimer;
public string Message
{
get { return richTextBox_Message.Text; }
set
{
richTextBox_Message.Invoke((MethodInvoker)(()
=> richTextBox_Message.Text = DateTime.Now + " " +
value + Environment.NewLine + richTextBox_Message.Text));
}
}
public Startup()
{
InitializeComponent();
}
private void ButtonStartClick(object sender, EventArgs e)
{
StartRemoteTruck();
}
private void ButtonPauseClick(object sender, EventArgs e)
{
if (_gpsTimer.Enabled) _gpsTimer.Enabled = false;
if (_ppsTimer.Enabled) _ppsTimer.Enabled = false;
if (_creditCardTimer.Enabled) _creditCardTimer.Enabled = false;
if (_iniTimer.Enabled) _iniTimer.Enabled = false;
ProcessIniFile.StopProcess();
}
public void StartRemoteTruck()
{
Message = "RemoteTruck started.";
if (Settings.GlobalSettings == null)
{
Message = "GlobalSettings was null or not loaded. Cannot continue.";
Logging.Log("GlobalSettings was null or not loaded. Cannot continue.", "RemoteTruck", Apps.RemoteTruckService);
Environment.Exit(0);
}
if (Settings.GlobalSettings.IniFileWatcherEnabled)
{
ProcessIniFile.StartProcess();
}
CreateTimers();
}
And in the ProcessIniFile.StartProcess() I have the code:
namespace SSS.RemoteTruckService.inifile
{
public static class ProcessIniFile
{
private static DateTime _iniLastWriteTime;
private static readonly string Inifile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "sss.ini");
private static FileSystemWatcher _watcher;
public static void StartProcess()
{
ReadIniFile();
SaveCurrentIniReadings();
CreateIniFileWatcher();
}
public static void StopProcess()
{
if (_watcher != null)
{
_watcher.EnableRaisingEvents = false;
_watcher = null;
}
}
private static void CreateIniFileWatcher()
{
_watcher = new FileSystemWatcher
{
Path = Environment.GetFolderPath(Environment.SpecialFolder.Windows),
NotifyFilter = NotifyFilters.LastWrite,
Filter = "sss.ini"
};
_watcher.Changed += SssIniWatcherChanged;
_watcher.EnableRaisingEvents = true;
}
I'd like to pass back the the calling form the status of the reads of the file watcher.
Maybe I'm overthinking this, but if I want to add to the Message on the main form, how do I get to it?
You can use Events for that. Your process can send events and your form can handle them.
More info: http://msdn.microsoft.com/en-us/library/awbftdfh.aspx
The simple but not pretty way I like to use is to make that part of the form static as well. For example, creating a static variable WriteMessage, and in your Form Load or Startup(), you can set it:
WriteMessage = (s) => Message = s;
Sure this has some issues, but it's a quick way to get it done. One of those issues is that, you may need to use Dispatcher.invoke if you're not on the UI thread.