5. diel - Prístup k okýnkům, mutex, fce messengera - isim
Global.cs
Tu to bude trošku rozsiahlejší, budú tu vnorené triedy, premenné a tak ďalej. Možno odporúčam si to potom roztriediť do viacerých súborov.
Enum dostupnosti môže byť nasledovné. Priradením hodnoty čísla, potom možno jednoducho pretypovať na integer a túto hodnotu získať. Tu to využívam ako určenie priority pri radení.
public enum Availability { Online = 1, Away = 2, DND = 3, Invisible = 4, Blocked = 5, Offline = 6 };
Prvý vnorená trieda obsahujúca inštancie okienok:
public static class OpenForms { public static MainForm mainForm; public static ChatForm chatForm; }
Ďalšia vnorená trieda je pre mutex - odosielanie signálu. Popísané tu: http://www.itnetwork.cz/...gle-instance
public static class SingleInstance { public const int HWND_BROADCAST = 0xffff; public static int WM_SHOWME; [DllImport("user32")] public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); [DllImport("user32")] public static extern int RegisterWindowMessage(string message); static SingleInstance() { WM_SHOWME = RegisterWindowMessage("ISIM_SHOW_FORM"); } public static void ShowForm() { SingleInstance.PostMessage( (IntPtr)SingleInstance.HWND_BROADCAST, SingleInstance.WM_SHOWME, IntPtr.Zero, IntPtr.Zero); } }
Teraz bude veľká vnorená trieda s funkciami messengera.
public static class ISIMFunctions {
Invoke
-> zaujímavá a užitočná metůdka, využívajúce
sa pri multi threading -> zásahu do iného threadu (okienka) z jinýho
threadu (okienka). Vzdám si ho a pracujem s ním. Tu je preto, aby som zaistil
spustenie okienka chatu na hlavnom vlákne. Inak by sa mohlo stať, že sa
metóda OpenChatForm zavolá z iného threadu a okienko by len probliklo -
akonáhle by thread skončil, okienko by sa zavrelo. Existuje aj asynchrónne
metóda BeginInvoke
- čo zjednodušene znamená, že sa
požiadavka pošle a ide sa ďalej, on sa časom vykoná na ďalšom vlákne,
takže sa na nič nečaká.
/// <summary> /// Přidání tabu případné otevření chat okýnka /// </summary> /// <param name="contact"></param> /// <param name="selectTab"></param> public static void OpenChatForm(ISIMContact contact, bool selectTab = false) { if (Global.OpenForms.chatForm == null) { // Abych zajistil otevření na hlavním threadu Global.OpenForms.mainForm.Invoke(new MethodInvoker(() => { Global.OpenForms.chatForm = new ChatForm(contact); Global.OpenForms.chatForm.Show(); Global.OpenForms.chatForm.Activate(); })); } else { Global.OpenForms.chatForm.BeginInvoke(new MethodInvoker(() => { Global.OpenForms.chatForm.chatTabs.AddTab(contact, selectTab); })); } }
()
-> je tzv. Lambda znak, používa sa pre definíciu
jednoriadkové metódy, ktorú možno použiť vnorené v metóde. Používa sa
namiesto delegátovi delegate()
kdůli kratšiemu zápisu.
object as MůjObject
je spôsob takéhoto C# like pretypovanie
objektu. Vlastne sa spýta, či je objekt toho typu ->
object is MůjObject ? (MůjObject)object : (MůjObject)null
.
Ovšem nemožno to použiť napríklad vo switch
, tuším že u
enum a nejakých ďalších prípadoch.
/// <summary> /// Přidání zprávy do chat okýnka dané konverzace a případné otevření okýnka /// </summary> /// <param name="contact"></param> /// <param name="message"></param> /// <param name="time"></param> public static void AddChatMessage(ISIMContact contact, string message, DateTime time, string from) { OpenChatForm(contact); Global.OpenForms.chatForm.BeginInvoke(new MethodInvoker(() => { (Global.OpenForms.chatForm.chatTabs.TabPages[contact.id] as ChatTabPage).AddChatMessage(contact, message, time, from); if (Global.OpenForms.chatForm.chatTabs.TabPages[contact.id] != Global.OpenForms.chatForm.chatTabs.SelectedTab) { contact.unreadedMessage = true; Global.OpenForms.chatForm.Invoke(new MethodInvoker(() => { Global.OpenForms.chatForm.Refresh(); })); Global.OpenForms.mainForm.Invoke(new MethodInvoker(() => { Global.OpenForms.mainForm.Refresh(); })); } })); }
Pre odosielanie správ sa urobí jedna univerzálna metóda, ktorá rozpozná, z ktorého protokolu ide požiadavku a podľa toho sa zariadi.
/// <summary> /// Odeslání zprávy kontaktu /// </summary> /// <param name="contact"></param> /// <param name="conversation"></param> /// <param name="message"></param> public static void SendChatMessage(ISIMContact contact, object conversation, string message) { if (conversation is SkypeContact.ContactObject) { try { (conversation as SkypeContact.ContactObject).conversation.PostText(message); } catch (Exception ex) { AddChatMessage(contact, "Nepodařilo se odeslat zprávu", DateTime.Now, "ISIM"); Console.WriteLine("msg send failed" + ex.Message); } } // nejprve se zkontroluje dle nějakého identifikátoru které knihovně daný objekt náleží if (conversation is XmppContact.ContactObject) { Global.OpenForms.mainForm.Invoke(new MethodInvoker(() => { // nastala chyba - odpojeno od serveru if (((conversation as XmppContact.ContactObject).xmppClient == null) || ((conversation as XmppContact.ContactObject).xmppClient.XmppConnectionState != agsXMPP.XmppConnectionState.SessionStarted)) Global.ISIMFunctions.AddChatMessage(contact, "Chyba při odesílání zprávy", DateTime.Now, "ISIM"); // lze odeslat jen asi 1000 znaků dlouho zprávu, pokud je delší splitne se na části foreach (string msg in message.SplitString(900)) (conversation as XmppContact.ContactObject).xmppClient.Send(new agsXMPP.protocol.client.Message(new agsXMPP.Jid(contact.id), MessageType.chat, msg)); })); } if (conversation is IcqContact.ContactObject) { // blbě kódování v ICQ message = message.RemoveDiacritics(); (conversation as IcqContact.ContactObject).session.Messaging.Send(new IcqSharp.Base.Message(new IcqSharp.Base.Contact(contact.id), IcqSharp.Base.MessageType.Outgoing, message)); } Global.ISIMFunctions.AddChatMessage(contact, message, DateTime.Now, myNick); }
Pri pridanie kontaktu alebo editáciu jeho dostupnosti sa zavolá metóda
Sort
sesortí kontakty podľa nášho komparátora ai prekreslí
ListView
čo ma celkom štvalo, BZE to preblikáva. Preto je dobré
používať BeginUpdate()
a EndUpdate()
ak robíme
viac operácií, ako napríklad pri hromadnom pridávaní kontaktov, zablokuje
to prekresľovanie urobím si čo chcem a potom to prekreslíme naraz.
public static void AddContact(ISIMContact contact) { Global.OpenForms.mainForm.BeginInvoke(new MethodInvoker(() => { if (!Global.OpenForms.mainForm.contactListView.Items.ContainsKey(contact.id)) { Global.OpenForms.mainForm.contactListView.Items.Add(new ContactListViewItem(contact)); if (contact.availability == Availability.Offline) Global.OpenForms.mainForm.contactListView.Items[contact.id].Group = Global.OpenForms.mainForm.contactListView.Groups["offlineListViewGroup"]; else Global.OpenForms.mainForm.contactListView.Items[contact.id].Group = Global.OpenForms.mainForm.contactListView.Groups["onlineListViewGroup"]; Global.OpenForms.mainForm.contactListView.Sort(); } })); } public static void EditContactAvailability(string id, Availability availability) { Global.OpenForms.mainForm.BeginInvoke(new MethodInvoker(() => { if (Global.OpenForms.mainForm.contactListView.Items.ContainsKey(id)) { (Global.OpenForms.mainForm.contactListView.Items[id] as ContactListViewItem).contact.availability = availability; if (availability == Availability.Offline) Global.OpenForms.mainForm.contactListView.Items[id].Group = Global.OpenForms.mainForm.contactListView.Groups["offlineListViewGroup"]; else Global.OpenForms.mainForm.contactListView.Items[id].Group = Global.OpenForms.mainForm.contactListView.Groups["onlineListViewGroup"]; Global.OpenForms.mainForm.contactListView.Sort(); } })); } public static void RemoveContact(string id) { Global.OpenForms.mainForm.Invoke(new MethodInvoker(() => { Global.OpenForms.mainForm.contactListView.Items.RemoveByKey(id); })); } }