Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 5 - Přístup k okýnkům, Mutex, fce messengeru - ISIM

Global.cs

Tady to bude trošku rozsáhlejší, budou zde vnořené třídy, proměnné a tak dál. Možná doporučuji si to pak roztřídit do více souborů.

Enum dostupnosti může být následující. Přiřazením hodnoty čísla, pak lze jednoduše přetypovat na integer a tuto hodnotu získat. Zde to využívám jako určení priority při řazení.

public enum Availability { Online = 1, Away = 2, DND = 3, Invisible = 4, Blocked = 5, Offline = 6 };

První vnořená třída obsahující instance okýnek:

public static class OpenForms
{
    public static MainForm mainForm;
    public static ChatForm chatForm;
}

Další vnořená třída je pro Mutex - odesílání signálu. Popsáno zde: 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);
    }
}

Teď bude velká vnořená třída s funkcemi messengeru.

public static class ISIMFunctions
{

Invoke -> zajímavá a užitečná metůdka, využívající se při multi threadingu -> zásahu do jiného threadu (okýnka) z jinýho threadu (okýnka). Přivlastním si ho a pracuji s ním. Zde je proto, abych zajistil spuštění okýnka chatu na hlavním vlákně. Jinak by se mohlo stát, že se metoda OpenChatForm zavolá z jiného threadu a okýnko by jen probliklo - jakmile by thread skončil, okýnko by se zavřelo. Existuje také asynchronní metoda BeginInvoke - což zjednodušeně znamená, že se požadavek pošle a jede se dál, on se časem vykoná na dalším vlákně, takže se na nic nečeká.

/// <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žívá se pro definici jednořádkové metody, kterou lze použít vnořeně v metodě. Používá se místo delegátu delegate() kdůli kratšímu zápisu.

object as MůjObject je způsob takového C# like přetypování objektu. Vlastně se zeptá, zda je objekt toho typu -> object is MůjObject ? (MůjObject)object : (MůjObject)null. Ovšem nelze to použít například ve switch, tuším že u enum a nějakých dalších případech.

/// <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(); }));
        }
    }));
}

Pro odesílání zpráv se udělá jedna univerzální metoda, která rozpozná, ze kterého protokolu jde požadavek a podle toho se zařídí.

/// <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);
}

Při přidání kontaktu nebo editaci jeho dostupnosti se zavolá metoda Sort sesortí kontakty dle našeho komparátoru a i překreslí ListView což mě celkem štvalo, bže to problikává. Proto je dobré používat BeginUpdate() a EndUpdate() pokud děláme více operací, jako například při hromadném přidávání kontaktů, zablokuje to překreslování udělám si co chci a pak to překreslím naráz.

    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);
        }));
    }
}

 

Předchozí článek
Interface pro kontakt, Adaptee Wrapper a komparátor - ISIM
Všechny články v sekci
Programujeme vlastní Instant Messenger ::ISIM::
Přeskočit článek
(nedoporučujeme)
Konverter, práce s textem - ISIM
Článek pro vás napsal David Jančík
Avatar
Uživatelské hodnocení:
Ještě nikdo nehodnotil, buď první!
Autor je vášnivý programátor. Nezná slovo "nelze", nebojí se zkoušet nepoznané a pronikat do nových technologií.
Aktivity