субота, 21 березня 2015 р.

Xamarin Forms: Getting started.

Не так давно, а щоб бути точнішим 2 місяці назад почалося моє знайомство з Xamarin.Forms. Мені як людині, що прийшла з Веб .NET, і з мобільних платформ використовувала лише Windows Phone і то на рівні користувача, було трохи незвично і важкувато вникати в деталі розробки під мобільні платформи типу Android та iOS.
Так склалося, що розпочали в компанії невеликий мобільний проект, вирішили вибрати Xamarin.Forms, щоб вбити двох зайців(Android and iOS) одним пострілом. Розбиратись у цій технології випало мені. Добре, що раніше мав справу з Silverlight та WPF, тож синтаксис XAML не був новинкою. Підхід розробки був вибраний MVVM, Event-based відкинув зразу, хоча повністю уникнути event-підходу не вдалося, але це нормально.
Вбити зразу двох зайців не вийшло, спочатку писав та тестував на Андроїді(телефон та таблетка), потім днів три тюнив UI для iPhone. Одне добре, функціонал працює на двох системах майже ідеально, тобто все, що написав під андроїд практично зразу запрацювало під iOS. Так, прийшлося писати різні класи(для кожної платформи) для роботи з файлами, pdf-документами, зате порадував SQLiteNet для роботи з БД, робота з WCF сервісами та підтримка async/await в PCL. Також тішить, що хоч Xamarin.Forms ще досить сира, уже є багато хороших open-source проектів, один з них XLabs. Використав його як MVVM-контейнер + багато хороших контролів та екстеншенів.
Звичайно, Forms не підходить для розробки крутих-швидких-анімаційних програм, але для бізнес-аплікацій саме то, особливо для людей, які хочуть(читай треба) швидко переключитися з web .net на mobile development.
Окремо про workflow розробки: Android простіше і швидше. Підключив девайс, чи поставив Android Player і voila, прямо з Xamarin Studio кодиш-запускаєш-правиш. Для iOS прийшлось ставити віртуальну машину з Маком, виділяти під нього 4Гб оперативної памяті, кодити в Visual Studio, а результат перевіряти на емуляторі у віртуальній машині, чи девайсі, підключеному до віртуальної машини. Нажаль. час на компіляцію і запуск великий. Дуже шкода, що немає UI Designer'a, бо фіксати UI ну дуже вже вимучує... Наразі все. Далі буде... буде більше конкретики і технічного матеріалу.

P.S: iOS набагато розумніше формує UI з XAML ніж Android. Був приємно здивований, що на підтягування затратив лише 3 дні, бо UI для Android вимучував біля 2-х тижнів.

пʼятниця, 14 травня 2010 р.

Групування в ASP.NET GridView server control

Усім відомо, що в контролі GridView немає фічі групування за ключовими полями. В неті також не так багато матеріалу по тому, як організувати "ручками" таку властивість, а про безплатні контроли уже мовчу.
Хоча ні, матеріалу таки є, але все, що мені попадалось, було якимось сируватим. Опрацювавши по частинах найдену інфу, я вирішив написати невеликий хелпер, що буде організовувати бажану фічу.
Поставлена задача: коректно опрацьовувати і формувати в контролі групові рядки, реагувати на пейджінг і саме основне - це групувати не тільки за одним ключовим полем, такби мовити мультигрупуваня.
Коду трохи багато, то ж не буду усього викладати, а опишу лише основне.
Принцип полягає в тому, щоб провіряти ключові поля, і, якщо ці поля співпадають, то залишати в попередньо організовані групі, якщо ні, то створювати нову групу і додавати до нашої таблиці груповий рядок.
Ось метод, котрий робить вищезгадану перевірку:
private bool EvaluateEquals(GridViewGroup g, object dataitem)
{
bool isEqual = false;
if (dataitem == null)
throw new NullReferenceException();
if (g.ActualValues != null)
{
isEqual = true;
for (int i = 0; i < g.Columns.Length; i++) { object currentValue = DataBinder.Eval(dataitem, g.Columns[i]); object groupValue = g.ActualValues[i]; if (currentValue != null && groupValue != null) { if (currentValue is DateTime) { if (((DateTime)currentValue) == (DateTime)groupValue) continue; else { isEqual = false; break; } } else if (currentValue is string) { if (currentValue.ToString() == groupValue.ToString()) continue; else { isEqual = false; break; } } else if (currentValue is Nullable)
{
if ((Nullable)currentValue == (Nullable)groupValue)
continue;
else { isEqual = false; break; }
}
}
else
if (currentValue == null && groupValue == null)//null and null is equal in this case
continue;
else
isEqual = false;
}
}
return isEqual;
}

В коді, що вище, застосовується приведення типів ключових полів та значень рядка з даними. Це для того, щоб забезпечити корректне виконання порівнянь значень, а не посилань. Останнє порівняння
застосовується для організації рівності null значень. Оскільки null != null, то if (currentValue == null && groupValue == null) забезпечить бажаний результат.
Основна функція процесу групування:
private void ProcessGroup(GridViewGroup g, GridViewRowEventArgs e)
{
// Checks if it's still in the same group values
if (e.Row.DataItem != null)
{
if (!EvaluateEquals(g, e.Row.DataItem))
{
// Another group values starts now
g.Reset();
g.SetActualValues(GetGroupRowValues(g, e.Row.DataItem));

string text = string.Empty;
GridViewRow newRow = InsertGridRow(e.Row);
int i = 0;
foreach (object v in g.ActualValues)
{
TableCell tc = new TableCell();
tc.Text = (v ?? string.Empty).ToString();
newRow.Cells.AddAt(i, tc);
text += (v ?? string.Empty).ToString() + " ";
i++;
}

// Triggers event GroupHeader
if (GroupHeaderEvent != null)
{
GroupHeaderEvent(g.Name, g.ActualValues, newRow);
}

}
}

}

g.Reset() - метод скидає попередню групу, а метод g.SetActualValues(GetGroupRowValues(g, e.Row.DataItem)) -записує фактичні значення ключових полів для новоствореної групи.
InsertGridRow(e.Row) - ще одна допоміжна функція, що додає новий рядок для відображення групових значень.
Тепер залишається останнє - використання вищевикладеного:
В класі веб-сторінки в обробнику події Init реєструєм групу таким чином:
GridViewHelper gvHelper = new GridViewHelper(gvMyGridView);
string[] items = new string[] { "ID", "Date", "Customer", "Location" }; // - визначаємо список ключових полів для групування, повинні співпадати з полями з датасорс
gvHelper.GroupHeader += new GroupEvent(gvHelper_GroupHeader); // - не обовязково, реакція на створення групи, можна використовувати наприклад для встановлення кольору рядка в таблиці ГрідВю
gvHelper.RegisterGroup(items, true, false);// - реєструєм Групу

Для коректного пейджинга потрібно не мало не багато:
public void Paginate()
{
foreach (GridViewGroup g in mGroups)
{
g.Reset();
}
}

Цей відкритий метод використовуєм в обробці пейджінга на сторінці.
От і все. Такий короткий опис основних функцій хелпера.
Хочу наголосити, що даний хелпер опрацьовує групування для кожної сторінки таблиці при пейджінгу, тобто при переході на наступну-поперелню сторінку групи обчислюються заново. Це приємливо у більшості випадків, хоча може бути необхідним і інший, а саме: необхідність організувати групування по всіх пейджах таблиці. На це потрібно набагато більше зусиль, часу і коду)), тож зараз над цим працюю. Також планую перенести весь код хелпера в кастом контрол. Якщо когось зацікавить - любязно поділюся контролкою)))...але це все "опосля".
Наостанок викладаю архів з хелпером.