I am using SignalR to implement a notification system to exchange information between my application instances. I have the following hub class:
[HubName("OpenHub")]
public class OpenHub:Hub
{
public void DetermineLength(string message)
{
Clients.All.RecieveNewInfo(newMessage);
//How to use something like the following line?
//concerning that Form1 is loaded at application startup
//and I should not create a new instance
//Form1.lstMessages.Add(newMessage);
}
}
Yet, I have to update some UI controls including a label and a listbox to log whatever new information that has arrived. Besides defining my class in my form's code, how can I update Form object to show these new information when I have my hub defined in a different class?
You can use public static property in you Program class or you Form1 class to hold the reference for it.
For example in you Program before using Application.Run(new Form1());
You can do this:
public static Form1 MainForm { get; set; }
and then in the Main()
MainForm = new Form1();
Application.Run(MainForm);
From the hub you can access you form now:
[HubName("OpenHub")]
public class OpenHub:Hub
{
public void DetermineLength(string message)
{
Clients.All.RecieveNewInfo(newMessage);
Program.MainForm.lstMessages.Add(newMessage);
}
}
Of course, that lstMessages should be public. or better you expose in your form some public method to communicate with it.
If your app is winform you can register to the hub with something like this :
var Connection = new HubConnection("yourSignalRServerUrl");
var HubProxy = Connection.CreateHubProxy("OpenHub");
HubProxy.On<string>("RecieveNewInfo", (message) =>
this.Invoke((Action)(() =>
Form1.lstMessages.Add(message);
);
await Connection.Start();
The namespace needed to use HubProxy is Microsoft.AspNet.SignalR.Client
This example comes from : https://code.msdn.microsoft.com/windowsdesktop/Using-SignalR-in-WinForms-f1ec847b
Related
Im new to xamarin/c#, im trying to make an application with login , and Im trying to pass the logged in userid inside the application, the question is , how do I pass or make the user id keeps floating inside after the login page? Should I keep passing it in every page using queryproperty or there's better way to keep it , like a specific file to to put it so that every page can call it?
You can use the Application.Properties collection to store things that need to be accessible to the entire application.
To store the user ID you would use
Application.Current.Properties("UserID") = UserID;
and to retrieve it you would use
UserID = Application.Current.Properties("UserID");
In C# it's not possible to define true global variables (meaning that they don't belong to any class). using a static class is a valid alternative option so you can create something like this:
public static class Globals
{
public Dictionary<int, UserObject> Users = new Dictionary<int, UserObject>();
}
Now, you'll be able to access The Users's dictionary property and add/remove/modify login users
Following Hans Kesting comment, Please note that An Xamarin app servers a single user at at time, so you can refactor the above from a dictionary to UserObject
Static classes - bad practic for contains info. You can use IoC-container. I don't know xamarin, if you have startup-class (how WPF), you can make ioc-container:
Install Autofac Install-Package Autofac -Version 5.0.0
Rigster user content:
class StartupClass
{
public static IContainer Container { get; set; }
public void OnStartup()
{
var containerBuilder = new ContainerBuilder();
var userContent = smthMethodForGiveUserContent();
containerBuilder.RegisterInstance<User>(userContent); //register UserType!
Container = containerBuilder.Build();
}
}
Resolve user content:
class SmthClass
{
public void Method()
{
using(var scope = StartupClass.Container.BeginLifetimeScope())
{
var userContent = scope.Resolve<User>(); //IT'S YOUR OBJECT, USE!!
//smth code..
}
}
}
The quickest way is to define a variable in App, it can be accessible to the entire project .
Because App itself has been defined inside Application class ,and it is a static property .
public partial class App : Xamarin.Forms.Application
{
public string UserID;
}
// set or get
(App.Current as App).UserID
I'm trying to make a chat bot for twitch and i want to make it in a Form so its very user friendly, i got the twitch communication done but now my form wont initialize. Please help.
namespace TwitchBotForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
IrcClient irc = new IrcClient("irc.twitch.tv", 6667, "z_bot909", "oauth:dn2tixd1xd7krggyn49ztw08hmfjea");
irc.joingRoom("z_dog909");
irc.sendChatMessage("Startup Complete");
while (true)
{
string message = irc.readMessage();
string[] splitMessage = message.Split('#');
if (message.Contains("!info"))
{
irc.sendChatMessage("Please Keep all commands LowerCase I made this bot Myself and i think its pretty cool. do !Help for Commands");
}
if (message.Contains("!me"))
{
irc.sendChatMessage(splitMessage[1].Split(':')[0]); //Username
}
}
}
}
}
You should not put this infinite loop in constructor of your form.
Check this article on how to run background thread with windows forms.
I have built a modular program using
http://www.codeproject.com/Articles/258681/Windows-Forms-Modular-App-using-MEF as a base and I have several of my modules working.
It is a MDI Windows Forms application and I need to call back to the host module for some stuff.
a) Location information for the MDI host window
b) Write to the status bar in the host window.
I have managed to get the application to compile but when I call the host functions it always gives me a null exception
I did look at Using MEF with C#, how do I call methods on the host, from the plugin?
which is where I got my line
public Exec.Core.Interfaces.IHost Host;
But host is always null so I get exceptions trying to access the members of MDIForm which is the host.
Even if I do public Exec.Core.Interfaces.IHost Host {get;set;}
This is the Host.
NameSpace Exec
{
[Export(typeof(Exec.Core.Interfaces.IHost))]
// MDIForm is the host.
public partial class MDIForm : Form, Exec.Core.Interfaces.IHost
{
///other stuff not related to the problem
// defined in public interface IHost
public Point myLocation()
{
return this.Location; // need the window location
}
// defined in public interface IHost
public IHost GetHost()
{ // is this what GetHost Should Return? Not sure
return this;
}
// defined in public interface IHost
public void SendMessage(string message)
{
SetStatusBar(message); // print a message to MDIForm status bar
}
}
}
Then is the IHosts.cs
namespace Exec.Core.Interfaces
{
public interface IHost
{
IHost GetHost();
void SendMessage(string message);
Point myLocation();
// MDIForm GetThis( ); /* this gives error. Can't resolve MDIForm
I don't know why and can't resolve.*/
}
}
This is one of the modules where I am trying to get stuff from the host
namespace Exec.Modules.Tasks
{
[Export]
public partial class frmTasks : Form
{
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
// unfortunately Host == NULL at this point
private void SendMessage (string message)
{
try
{
Host.SendMessage(message); <Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private IHost WhichHost()
{
try
{ /// not really sure what will be returned here
return GetHost();<Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private Point Location()
{
try
{
return mylocation(); <Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
And finally this is how I put all of the objects together in ModuleHandler.cs
This is pretty much taken from the codeproject above with some seperation of some method calls into 2 pieces so I could see why it was dying.
namespace Exec.Core
{
[Export(typeof(IModuleHandler))]
public class ModuleHandler : IDisposable, IModuleHandler
{
[ImportMany(typeof(IModule), AllowRecomposition = true)]
// The ModuleList will be filled with the imported modules
public List<Lazy<IModule, IModuleAttribute>> ModuleList
{ get; set; }
[ImportMany(typeof(IMenu), AllowRecomposition = true)]
// The MenuList will be filled with the imported Menus
public List<Lazy<IMenu, IModuleAttribute>> MenuList { get; set; }
[Import(typeof(IHost))]
// The imported host form
public IHost Host { get; set; }
AggregateCatalog catalog = new AggregateCatalog();
public void InitializeModules()
{
// Create a new instance of ModuleList
ModuleList = new List<Lazy<IModule, IModuleAttribute>>();
// Create a new instance of MenuList
MenuList = new List<Lazy<IMenu, IModuleAttribute>>();
// Foreach path in the main app App.Config
foreach (var s in ConfigurationManager.AppSettings.AllKeys)
{
if (s.StartsWith("Path"))
{
// Create a new DirectoryCatalog with the path loaded from the App.Config
DirectoryCatalog cataloglist = new DirectoryCatalog(ConfigurationManager.AppSettings[s], "jobexe*.dll");
catalog.Catalogs.Add(cataloglist);
}
}
// Create a new catalog from the main app, to get the Host
catalog.Catalogs.Add( new AssemblyCatalog(System.Reflection.Assembly.GetCallingAssembly()));
// Create a new catalog from the ModularWinApp.Core
DirectoryCatalog catalogExecAssembly = new DirectoryCatalog( System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location ), "exe*.dll");
catalog.Catalogs.Add(catalogExecAssembly);
// Create the CompositionContainer
CompositionContainer cc = new CompositionContainer(catalog);
try
{
cc.ComposeParts(this);
}
catch (ReflectionTypeLoadException e)
{ MessageBox.Show(e.ToString()); }
catch (ChangeRejectedException e)
{ MessageBox.Show(e.ToString()); }
}
}
}
So again, the modules work independently but are unable to call back to the host. Wondering what I am doing wrong.
Thanks in advance for any help
One final thing that may have something to do with the issue.
Here is the code that starts the program
public static ModuleHandler _modHandler = new ModuleHandler();
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Initialize the modules. Now the modules will be loaded.
_modHandler.InitializeModules();
// this goes straight to class MDIForm() constructor
Application.Run(_modHandler.Host as Form);
}
Colin
You instantiate your ModuleHandler manually and then call InitializeModules, where a catalog is created and passed to a new composition container. Then, this container is used to satisfy all the imports of that particular ModuleHandler instance through the line:
cc.ComposeParts(this);
This tells MEF to look for Import attributes and populate the decorated properties with instances of classes decorated with the corresponding Export attributes.
What you are missing is the analogous call to populate your frmTasks objects. Thus, the following Import is not satisfied and the property is null:
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
You have several options among which I'd look into the following two:
Modify the IModule interface so that you can explicitly pass an IHost to the modules. Then, in the InitializeModules, after the call to ComposeParts, iterate over the composed modules passing them the host instance. This accounts for setting the Host property through the IModule interface. You could also stick to the MEF imported property by putting it in the IModule interface and calling ComposeParts for each module instance.
Expose the container through a ServiceLocator and get the IModuleHandler instance from the modules to access the Host property.
I have an answer, I just don't think its the right one.
On my question I edited it and added the main program but i did not add its class.
It looks like
namespace Exec
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
//Create a new instance of ModuleHandler. Only one must exist.
public static ModuleHandler _modHandler = new ModuleHandler();
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Initialize the modules. Now the modules will be loaded.
_modHandler.InitializeModules();
Application.Run(_modHandler.Host as Form);
}
}
}
I was debugging and I found that in _modHandler.InitializeModules();
IHost Host was set, and its part of
public static ModuleHandler _modHandler = new ModuleHandler();
and everything here is static but not accessable. So I changed the class signature to public to make it global (dirty word I know)
public static class Program
and then in
namespace Exec.Modules.Tasks
in the Load_Form event I added a line to initialize Host.
public partial class frmTasks : Form
{
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
private void Load_Form(object sender, EventArgs e)
{
Host = Program._modHandler.Host.GetHost; << added this to initialize host
other stuff....
}
other stuff that now works
}
I don't think that this is how its supposed to work. I think that I should be able to populate this through the interfaces and modules...
Comments?
I'm working on a legacy application that's written using Silverlight 5, The application contains lot's of anti-patterns and bad practices. I'm responsible for adding real-time interactions (such as notification) using SingalR.
By the way, They're using these WCF RIA Services for interacting with authentication.
They have a Main page, this page is the place where I'm getting user's notification and show them for logged in users:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
//...
}
}
So as you can see I didn't set DataContext property as long as user is logged in, I need to set MainPage's DataContext after a user logs in to application, So I have to do that in LoginOperation_Completed inside LoginForm page:
public partial class LoginForm : StackPanel
{
private LoginRegistrationWindow parentWindow;
private LoginInfo loginInfo = new LoginInfo();
public LoginForm()
{
InitializeComponent();
//...
}
private void LoginOperation_Completed(LoginOperation loginOperation)
{
if (loginOperation.LoginSuccess)
{
// Here I need to access MainPages's DataContext property and set it with my ViewModel
}
}
}
Now my question is that, how can I set MainPage's DataContext property inside another class (in this case LoginFrom)?
I have also tried to give an ID to my MainPage user control and access it like this:
mainPage.DataContext = new NotificationItemViewModel();
But the compiler gives me this error:
The name 'mainPage' does not exist in the current context
I finally figured out How to solve my question, There is a simple way to achieve this, I should have created the static instance of the MainPage class in the class itself:
public partial class MainPage : UserControl
{
public static MainPage Instance { get; private set; }
public MainPage()
{
InitializeComponent();
Instance = this;
}
}
Now I can access to the MainPage's DataContext this way:
MainPage.Instance.DataContext = new NotificationItemViewModel();
You need to name your MainPage UserControl where you pasted it in LoginForm XAML. Not in the definition of MainPage.
I have a wpf app I have registered as a URI Scheme by doing the following.
HKEY_CLASSES_ROOT
-->myappname
-->shell
-->open
-->command
(Default) = "c:\pathtomyapp\app.exe"
Fantastic! However, my application enforces that only one instance can run at a time. How can I detect that my app is already running and for example bring it to the foreground?
You can use a named mutex to detect that application is already running. Or, if you have a GUI app, you can inherit your form from VisualBasic's SingleInstance application , and it will do routhgly the same for you.
public class SingleInstanceController
: WindowsFormsApplicationBase
{
public SingleInstanceController()
{
// Set whether the application is single instance
this.IsSingleInstance = true;
this.StartupNextInstance += new
StartupNextInstanceEventHandler(this_StartupNextInstance);
}
void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e)
{
// Here you get the control when any other instance is
// invoked apart from the first one.
// You have args here in e.CommandLine.
// You custom code which should be run on other instances
}
protected override void OnCreateMainForm()
{
// Instantiate your main application form
this.MainForm = new Form1();
}
}
[STAThread]
static void Main(string[] args)
{
SingleInstanceController controller = new SingleInstanceController();
controller.Run(args);
}
It does not matter whenever you write your code in C#, as this class is avaliable as a part of .Net framework and for all languages.
And here is a wrapper for the WPF