Porting SH1106 Oled Driver - 128 x 64 / 128 x 32 Screen is garbled but partially responsive
While your initialization routine looks fine to me (comparing to the datasheet and as evidenced by the fact the display turns on), what doesn't look right is your drawing routine:

//set column address
dcPin.Write(DisplayCommand);
SendCommandB(0x21);
SendCommandB(0);
SendCommandB((byte)(Width - 1));

//set page address
SendCommandB(0x22);
SendCommandB(0);
SendCommandB((byte)(_pages - 1));


The commands 0x21 and 0x22 don't correspond to any commands I can see in the datasheet.  They look more like commands more commonly seen with ILIxxxx or SSDxxxx screens to create an "addressable window" from 0,0 to Width-1, _pages-1.

Instead you should be using the same commands you used in the setup routine to set the current col / page coordinate in RAM to write to.

Commands (0x00 | (col &amp; 0x0F)) and (0x10 | (col &gt;&gt; 4)) set the column position, and (0xB0 | (page &amp; 0x0F)) set the page number.

You then write all 128 bytes for the current page before moving on to the next page.  This means you will have to do it a page at a time, something like:

for (ushort page = 0; page &lt; 4; page++) {

    // Set the current RAM pointer to the start of the currently
    // selected page.
    dcPin.Write(DisplayCommand);
    sendCommandB(0x00); // Set column number 0 (low nibble)
    sendCommandB(0x10); // Set column number 0 (high nibble)
    sendCommandB(0xB0 | (page &amp; 0x0F)); // Set page number

    // Send a single page (128 bytes) of data.
    // Without knowing the rest of your program I don't know the right
    // data sending routines to use, so I made them up. Change it to
    // do it how your program expects.  Maybe with your SendArray
    // function.

    dcPin.Write(DisplayData);
    for (ushort col = 0; col &lt; 128; col++) {
        sendDataB(displayBuffer[page * 128 + col]);
    }
}


Note that this method is very similar to how the KS0108 GLCD drivers work.  Each byte of the page represents 8 pixels on the screen so the screen, at 32 pixels high, is split into 4 pages, where each page is 8 pixels, or one byte, high.

The effect you are currently seeing is because you are never changing the current page number (0) so you are always writing your data to the first page.  This loops around multiple times, so you end up writing all 4 pages to the same strip of the display ending up with the last page being displayed, which is the last 8 lines of your display data.  The rest of the display is never being touched and just contains whatever random data was in the RAM at power-on.