Payback – nowy program lojalnościowy wystartował

Wspólnymi siłami Agencji Reklamowej S4 i Loyalty Partners przygotowaliśmy polską wersję serwisu Payback.de. Dzisiaj ten, nowy w naszym kraju, program oficjalnie wystartował – wpadki nie zaliczono :) Daje on jego uczestnikom możliwość zbierania na jedną kartę punktów lojalnościowych z wielu różnych źródeł – na starcie do programu należą m.in. Allegro, Real, BP, Orange i TPSA czy BZ WBK. Pierwsze komentarze w sieci można znaleźć np. pod artykułem na gazeta.pl czy na blogu Macieja Samcika.

Koniec akcji PomagamyRazem.pl

Zakończyła się kampania społeczna Stowarzyszenia Droga i Bezpieczeństwo. W ramach tej akcji Stowarzyszenie zbierało środki na pomoc ofiarom wypadków drogowych. Zakres działań obejmował spot w TV, informacje radiowe i prasowe, a także stronę internetową, którą zaprogramowałem wraz z mechanizmem obsługi SMSów. Każdy wysłany SMS zasilał konto fundacji, a na stronie, w czasie rzeczywistym, zapalał nową gwiazdę. Archiwum projektu można obejrzeć na serwerze Epeironu.

Monitoring stron internetowych

Uruchomiłem nową usługę w internecie, a w zasadzie przywróciłem do życia bardzo stary projekt. Jest to monitoring stron www, którego zadaniem jest kontrola pozycji stron w wyszukiwarkach internetowych oraz kontrola działania tych stron.

Projekt już kiedyś był zrealizowany – kilka lat temu, jednak chyba wtedy było zbyt wcześnie na tego typu usługę. W zasadzie szkoda – wtedy byłem pierwszy w polskim internecie, mogłem wytrwać i mieć dzisiaj ugruntowaną pozycję. Obecnie istnieje na rynku spora konkurencja. Piszę to jako zachętę dla was do działania – masz pomysł, to go realizuj i nie poddawaj się po pierwszych trudnościach.

Jak zrobić gradientowane tło kontrolki?

Należy nadpisać metodę OnPaintBackground() i samodzielnie zaprogramować rysowanie tła. Do rysowania gradientów można posłużyć się klasą LinearGradientBrush, np.:

using  System.Drawing.Drawing2D;

override protected void OnPaintBackground(PaintEventArgs e)
{
   LinearGradientBrush brush = 
   new System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle, Color.Red, Color.White, 0f);
   e.Graphics.FillRectangle(brush, ClientRectangle);
}

Lista komunikatów Windows

Nawiązując do poprzedniego postu poniżej wklejam listę komunikatów windows.

Komunikaty windows:

WM_NULL = 0x00
WM_CREATE = 0x01
WM_DESTROY = 0x02
WM_MOVE = 0x03
WM_SIZE = 0x05
WM_ACTIVATE = 0x06
WM_SETFOCUS = 0x07
WM_KILLFOCUS = 0x08
WM_ENABLE = 0x0A
WM_SETREDRAW = 0x0B
WM_SETTEXT = 0x0C
WM_GETTEXT = 0x0D
WM_GETTEXTLENGTH = 0x0E
WM_PAINT = 0x0F
WM_CLOSE = 0x10
WM_QUERYENDSESSION = 0x11
WM_QUIT = 0x12
WM_QUERYOPEN = 0x13
WM_ERASEBKGND = 0x14
WM_SYSCOLORCHANGE = 0x15
WM_ENDSESSION = 0x16
WM_SYSTEMERROR = 0x17
WM_SHOWWINDOW = 0x18
WM_CTLCOLOR = 0x19
WM_WININICHANGE = 0x1A
WM_SETTINGCHANGE = 0x1A
WM_DEVMODECHANGE = 0x1B
WM_ACTIVATEAPP = 0x1C
WM_FONTCHANGE = 0x1D
WM_TIMECHANGE = 0x1E
WM_CANCELMODE = 0x1F
WM_SETCURSOR = 0x20
WM_MOUSEACTIVATE = 0x21
WM_CHILDACTIVATE = 0x22
WM_QUEUESYNC = 0x23
WM_GETMINMAXINFO = 0x24
WM_PAINTICON = 0x26
WM_ICONERASEBKGND = 0x27
WM_NEXTDLGCTL = 0x28
WM_SPOOLERSTATUS = 0x2A
WM_DRAWITEM = 0x2B
WM_MEASUREITEM = 0x2C
WM_DELETEITEM = 0x2D
WM_VKEYTOITEM = 0x2E
WM_CHARTOITEM = 0x2F

WM_SETFONT = 0x30
WM_GETFONT = 0x31
WM_SETHOTKEY = 0x32
WM_GETHOTKEY = 0x33
WM_QUERYDRAGICON = 0x37
WM_COMPAREITEM = 0x39
WM_COMPACTING = 0x41
WM_WINDOWPOSCHANGING = 0x46
WM_WINDOWPOSCHANGED = 0x47
WM_POWER = 0x48
WM_COPYDATA = 0x4A
WM_CANCELJOURNAL = 0x4B
WM_NOTIFY = 0x4E
WM_INPUTLANGCHANGEREQUEST = 0x50
WM_INPUTLANGCHANGE = 0x51
WM_TCARD = 0x52
WM_HELP = 0x53
WM_USERCHANGED = 0x54
WM_NOTIFYFORMAT = 0x55
WM_CONTEXTMENU = 0x7B
WM_STYLECHANGING = 0x7C
WM_STYLECHANGED = 0x7D
WM_DISPLAYCHANGE = 0x7E
WM_GETICON = 0x7F
WM_SETICON = 0x80

WM_NCCREATE = 0x81
WM_NCDESTROY = 0x82
WM_NCCALCSIZE = 0x83
WM_NCHITTEST = 0x84
WM_NCPAINT = 0x85
WM_NCACTIVATE = 0x86
WM_GETDLGCODE = 0x87
WM_NCMOUSEMOVE = 0xA0
WM_NCLBUTTONDOWN = 0xA1
WM_NCLBUTTONUP = 0xA2
WM_NCLBUTTONDBLCLK = 0xA3
WM_NCRBUTTONDOWN = 0xA4
WM_NCRBUTTONUP = 0xA5
WM_NCRBUTTONDBLCLK = 0xA6
WM_NCMBUTTONDOWN = 0xA7
WM_NCMBUTTONUP = 0xA8
WM_NCMBUTTONDBLCLK = 0xA9

WM_KEYFIRST = 0x100
WM_KEYDOWN = 0x100
WM_KEYUP = 0x101
WM_CHAR = 0x102
WM_DEADCHAR = 0x103
WM_SYSKEYDOWN = 0x104
WM_SYSKEYUP = 0x105
WM_SYSCHAR = 0x106
WM_SYSDEADCHAR = 0x107
WM_KEYLAST = 0x108

WM_IME_STARTCOMPOSITION = 0x10D
WM_IME_ENDCOMPOSITION = 0x10E
WM_IME_COMPOSITION = 0x10F
WM_IME_KEYLAST = 0x10F

WM_INITDIALOG = 0x110
WM_COMMAND = 0x111
WM_SYSCOMMAND = 0x112
WM_TIMER = 0x113
WM_HSCROLL = 0x114
WM_VSCROLL = 0x115
WM_INITMENU = 0x116
WM_INITMENUPOPUP = 0x117
WM_MENUSELECT = 0x11F
WM_MENUCHAR = 0x120
WM_ENTERIDLE = 0x121

WM_CTLCOLORMSGBOX = 0x132
WM_CTLCOLOREDIT = 0x133
WM_CTLCOLORLISTBOX = 0x134
WM_CTLCOLORBTN = 0x135
WM_CTLCOLORDLG = 0x136
WM_CTLCOLORSCROLLBAR = 0x137
WM_CTLCOLORSTATIC = 0x138

WM_MOUSEFIRST = 0x200
WM_MOUSEMOVE = 0x200
WM_LBUTTONDOWN = 0x201
WM_LBUTTONUP = 0x202
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDOWN = 0x204
WM_RBUTTONUP = 0x205
WM_RBUTTONDBLCLK = 0x206
WM_MBUTTONDOWN = 0x207
WM_MBUTTONUP = 0x208
WM_MBUTTONDBLCLK = 0x209
WM_MOUSEWHEEL = 0x20A
WM_MOUSEHWHEEL = 0x20E

WM_PARENTNOTIFY = 0x210
WM_ENTERMENULOOP = 0x211
WM_EXITMENULOOP = 0x212
WM_NEXTMENU = 0x213
WM_SIZING = 0x214
WM_CAPTURECHANGED = 0x215
WM_MOVING = 0x216
WM_POWERBROADCAST = 0x218
WM_DEVICECHANGE = 0x219

WM_MDICREATE = 0x220
WM_MDIDESTROY = 0x221
WM_MDIACTIVATE = 0x222
WM_MDIRESTORE = 0x223
WM_MDINEXT = 0x224
WM_MDIMAXIMIZE = 0x225
WM_MDITILE = 0x226
WM_MDICASCADE = 0x227
WM_MDIICONARRANGE = 0x228
WM_MDIGETACTIVE = 0x229
WM_MDISETMENU = 0x230
WM_ENTERSIZEMOVE = 0x231
WM_EXITSIZEMOVE = 0x232
WM_DROPFILES = 0x233
WM_MDIREFRESHMENU = 0x234

WM_IME_SETCONTEXT = 0x281
WM_IME_NOTIFY = 0x282
WM_IME_CONTROL = 0x283
WM_IME_COMPOSITIONFULL = 0x284
WM_IME_SELECT = 0x285
WM_IME_CHAR = 0x286
WM_IME_KEYDOWN = 0x290
WM_IME_KEYUP = 0x291

WM_MOUSEHOVER = 0x2A1
WM_NCMOUSELEAVE = 0x2A2
WM_MOUSELEAVE = 0x2A3

WM_CUT = 0x300
WM_COPY = 0x301
WM_PASTE = 0x302
WM_CLEAR = 0x303
WM_UNDO = 0x304

WM_RENDERFORMAT = 0x305
WM_RENDERALLFORMATS = 0x306
WM_DESTROYCLIPBOARD = 0x307
WM_DRAWCLIPBOARD = 0x308
WM_PAINTCLIPBOARD = 0x309
WM_VSCROLLCLIPBOARD = 0x30A
WM_SIZECLIPBOARD = 0x30B
WM_ASKCBFORMATNAME = 0x30C
WM_CHANGECBCHAIN = 0x30D
WM_HSCROLLCLIPBOARD = 0x30E
WM_QUERYNEWPALETTE = 0x30F
WM_PALETTEISCHANGING = 0x310
WM_PALETTECHANGED = 0x311

WM_HOTKEY = 0x312
WM_PRINT = 0x317
WM_PRINTCLIENT = 0x318

WM_HANDHELDFIRST = 0x358
WM_HANDHELDLAST = 0x35F
WM_PENWINFIRST = 0x380
WM_PENWINLAST = 0x38F
WM_COALESCE_FIRST = 0x390
WM_COALESCE_LAST = 0x39F
WM_DDE_FIRST = 0x3E0
WM_DDE_INITIATE = 0x3E0
WM_DDE_TERMINATE = 0x3E1
WM_DDE_ADVISE = 0x3E2
WM_DDE_UNADVISE = 0x3E3
WM_DDE_ACK = 0x3E4
WM_DDE_DATA = 0x3E5
WM_DDE_REQUEST = 0x3E6
WM_DDE_POKE = 0x3E7
WM_DDE_EXECUTE = 0x3E8
WM_DDE_LAST = 0x3E8

WM_USER = 0x400
WM_APP = 0x8000

DoubleClick na ListView nie działa na pustym obszarze

Kto by się spodziewał, programiści frameworka .NET doszli do wniosku, że zdarzenia Click oraz DoubleClick (i pochodne) mają działać tylko po kliknięciu myszką w istniejące elementy listy. Jakie to powoduje ograniczenia? Otóż wymyśliłem sobie, że podwójne kliknięcie w puste miejsce kontrolki ListView powinno powodować utworzenie nowego elementu. Z rozpaczą jednak stwierdziłem, że to nie działa….

…zacząłem szukać w google…

…i zdruzgotany nic nie znalazłem – poza – kilkoma poradami, aby wprowadzić własną obsługę za pomocą Timera i MouseDown/MouseUp. Do bani.

A rozwiązanie istnieje i jest ono całkiem eleganckie. Należy utworzyć własną kontrolkę rozszerzającą ListView, a następnie nadpisać metodę

protected override void WndProc(ref Message m)

takim kawałkem kodu:

if (m.Msg == 0x203) //WM_LBUTTONDBLCLK
{
this.OnDoubleClick(MouseEventArgs.Empty);
}
else
{
base.WndProc(ref m);
}

I już. Przechwytujemy wszystkie komunikaty i w przypadku gdy jest to podwójne kliknięcie, wywołujemy zawsze zdarzenie OnDoubleClick. Podobnie można zrobić dla pojedynczego kliknięcia, tylko sobie ustalcie ID komunikatu.

Maziagenerator

W toku jakże intensywnych prac nad efektami specjalnymi we flashu, przez przypadek stworzyłem maziageneratora – program, który także tobie pozwoli poczuć się prawdziwym impresjonistą.

Tak się kończą zabawy z Bitmap.draw, BlendMode.OVERLAY i krzywymi lissajou:

(kliknij i zacznij rysować)

Laden, bitte warten!

Sympatyczna strona na kampanię promocyjną firmy Komandor. I chociaż, jak to w życiu bywa, klient drastycznie zmienił naszą wstępną koncepcję, to mimo tego udało się na tyle zachować ducha strony, że przy jej pisaniu miałem odpowiednią ilość motywującego “funu” :)

Chcecie obejrzeć stronę na żywo? Klikajta w obrazek!

C# .NET – pobieranie pliku z serwera HTTP

W jaki sposób w C# zrealizować ściąganie pliku z serwera www? Rozwiązanie jest proste, nawet, zbyt proste :) Oto najkrótszy z możliwych sposobów:

using System.Net;
 
namespace DownloadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            WebClient webClient = new WebClient();
            try
            {
                webClient.DownloadFile("http://server/file", "myFileName");
            }
            catch (WebException e)
            {
                //some error
            }
        }
    }
}

Metoda DownloadFile z klasy webClient przyjmuje dwa parametry: String lub URI z adresem sieciowym pliku oraz String z nazwą pod jaką plik zostanie zapisany lokalnie. Jednak ta metoda jest częściowo nieelegancka – blokuje całkowicie wątek aż do zakończenia pobierania pliku. Nie możemy w tym czasie odebrać żadnych eventów (np. użytkownik nie będzie w stanie przerwać operacji ściągania) ani np. informować o postępie. Zamiast niej możemy jednak użyć podobnej metody – DownloadFileAsync(Uri, String):

using System;
using System.Net;
 
namespace DownloadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            WebClient webClient = new WebClient();
 
            webClient.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
            webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
 
            try
            {
                webClient.DownloadFileAsync(new Uri("http://server/file"), "myFileName");
            }
            catch (WebException e)
            {
                //stało się coś bardzo niedobrego ;)
            }
        }
 
        static void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            //zobaczmy ile procent pobrano: 
            Console.WriteLine(e.ProgressPercentage.ToString());
        }
 
        static void webClient_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            //zakończono pobieranie pliku
        }
    }
}

Warto zapamiętać, że za pomocą DownloadFileAsync nie możemy w jednym wątku ściągać jednocześnie więcej niż jednego pliku – w przypadku próby dokonania takiej operacji otrzymamy wyjątek. Dlatego z pobieraniem kolejnego pliku musimy poczekać do zakończenia pobierania poprzedniego.