Архив рубрики: C

Изменение в данных и текущей команды во время отладки

Как видно из картинки, 10 меньше или равно 5. Под катом два способа отличных от редактирования картинки, которыми можно получить такой результат. Возможности эти старые, просто мне попался тут на днях человек не знающий про них.


Первый вариант полезен, когда во время отладки сложно получить из окружения какие-то данные, а нам нужно проверить именно на них. В том месте где нам нужны данные, ставим точку останова и запускаем приложение:
Затем наводим мышку на интересующую нас переменную, чтобы выскочило окно с ее значением:
И переместив мышку кликаем на значении (если объект сложный, то можно путешествовать по его свойствам, иногда бывают проблемы, но в целом можно редактировать достаточно много чего):
Нажимаем Enter и все, программа идет по пути когда a <= 5.
Второй вариант еще проще, даже картинок не буду прикладывать. Ставим точку останова, запускаем приложение и когда доходим до точки, просто хватаем желтую стрелку (на предыдущей картинке на точке останова) мышкой и переставляем в нужное нам место. Это способ, как правило дополненный первым, нужен для того, чтобы пропустить некий функционал который взаимодействует с частью которой нет (не реализована или отсутствует в текущий момент).

[Xamarin] 2. Собираем приложения и делаем главное меню "Гамбургер"

Продолжаем разговор, т.к. собрать приложения это достаточно просто, то кроме этого добавим в приложение меню "Гамбургер". Поехали.

Создаем новый проект в студии выбрав Cross Platform App (Xamarin):
В открывшемся окне я оставил пустое приложение, но вот шаринг кода выбрал на основе PLC. Принципиальная разница в том, как организуется доступ к платформозависимым вещам. В Shared Project, это директива #if.
После нажатия на принять и некоторого времени (если вы это делаете в первый раз, то выскочит предупреждение, что надо бы операционную систему перевести в режим разработчика, плюс выскочит окошко подключения к устройству на котором компилировать iOs решение, т.к. мне пока это не интересно, то я просто закрыл это окно. В итоге создается решение содержащее 4 проекта:
Как не сложно догадаться, три из них под платформы, ну и первое в списке, это разделяемая сборка код из которой будет использоваться в остальных решениях.
Следующим шагом я выгрузил проект с iOs приложением, запустил билд и получил ошибку Could not find android.jar for API Level 26. This means the Android SDK platform for API Level 26 is not installed. Either install it in the Android SDK Manager (Tools > Open Android SDK Manager...), or change your Xamarin.Android project to target an API version that is installed.
В принципе, все логично, т.к. я устанавливал SDK для Android версии 7.1.1, а ей соответствует 25 версия. Заходим в настройки Android проекта и меняем версию:
Все, можно запускать UWP и Android приложение. Эмулятор по прежнему долго грузиться, но мы уже можем убедиться, что приложения работают и показываю жизнеутверждающий текст про "Добро пожаловать...".
Как я уже сказал, это не очень интересно, поэтому добавлю заголовок в приложение и главное меню "Гамбургкер".
Создаем в корневом проекте папки Views и ViewModels. В папку ViewModels добавляем класс MenuViewModel, в папку Views добавляем Content Page для самого меню и две Content Page для показа как работают переходы (Home и Second):
На вьюхах Home и Second я просто поменял текст:
Как я уже сказал, они нужны только для того, чтобы было понятно на какой мы странице.
Меняем нашу главную страницу, делая ее потомком MasterDetailPage. Для этого меняем предка в cs файле и удалив все содержимое, меняем корневой тег. Вот такой получается XAML:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Adjutant"
             x:Class="Adjutant.MainPage">

</MasterDetailPage>
И вот так cs:

Начинаем реализовывать меню. Для этого нам нужно знать, на какой мы странице сейчас находимся. Для упрощения примера, я не буду усложнять с правильной реализацией навигации и просто добавлю в класс App три свойства (для хранения ссылки на главное окно, для хранения ссылки которая сейчас показывается и признак развернутости меню):
public partial class App : Application
{

    public staticNavigationPage NavigationPage { get; private set; }
    private static MainPage RootPage;
    public static bool MenuIsPresented
    {
        get
        {
            return RootPage.IsPresented;
        }
        set
        {
            RootPage.IsPresented = value;
        }

    }
В ViewModel добавляем следующий код:
public class MenuViewModel
{
    public ICommand GoHomeCommand { get; set; }
    public ICommand GoSecondCommand { get; set; }

    public MenuViewModel()
    {
        GoHomeCommand = newCommand(GoHome);
        GoSecondCommand = newCommand(GoSecond);
    }

    void GoHome(object obj)
    {
        App.NavigationPage.Navigation.PopToRootAsync();
        App.MenuIsPresented = false;
    }

    void GoSecond(object obj)
    {
        App.NavigationPage.Navigation.PushAsync(new SecondView());
        App.MenuIsPresented = false;
    }

}
Как видно, у нас просто две команды. Одна для перехода на домашнюю страницу, вторая для перехода на вторую.
Самое интересное. Вьюха с меню. В XAML добавляем две кнопки:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Adjutant.Views.MenuView">
    <ContentPage.Content>
        <StackLayout BackgroundColor="Gray">
            <Button Text="Домой" TextColor="White" BackgroundColor="Green" Command="{Binding GoHomeCommand}" />
            <Button Text="Вторая страница" TextColor="White" BackgroundColor="Navy" Command="{Binding GoSecondCommand}" />
        </StackLayout>
    </ContentPage.Content>

</ContentPage>
А в cs, опять же, чтобы не усложнять пример, добавим создание ViewModel:
public partial class MenuView : ContentPage
{
    public MenuView()
    {
        BindingContext = newMenuViewModel();
        Title = "Menu";
        InitializeComponent();
    }

}
Осталось только поправить создание приложения. Дописываем конструктор класса App:
public App()
{
    InitializeComponent();
    var menuPage = new MenuView();
    NavigationPage = newNavigationPage(new HomeView());
    RootPage = new MainPage();
    RootPage.Master = menuPage;
    RootPage.Detail = NavigationPage;
    MainPage = RootPage;

}
Запускаем. Вот так это выглядит в эмуляторе после запуска:
А вот так после тапа на "гамбургере":
При переходе на вторую страницу меню пропадает и заменяется стрелкой назад:
В целом все нормально ровно до тех пор, пока не запустим UWP:
Нет "гамбургера", меню показывается всегда... Вот такие они, Xmarin.Forms - одинаковые на всех платформах :)
Ладно, в следующий раз поговорим о моделях навигации.

[Xamarin] 2. Собираем приложения и делаем главное меню "Гамбургер"

Продолжаем разговор, т.к. собрать приложения это достаточно просто, то кроме этого добавим в приложение меню "Гамбургер". Поехали.

Создаем новый проект в студии выбрав Cross Platform App (Xamarin):
В открывшемся окне я оставил пустое приложение, но вот шаринг кода выбрал на основе PLC. Принципиальная разница в том, как организуется доступ к платформозависимым вещам. В Shared Project, это директива #if.
После нажатия на принять и некоторого времени (если вы это делаете в первый раз, то выскочит предупреждение, что надо бы операционную систему перевести в режим разработчика, плюс выскочит окошко подключения к устройству на котором компилировать iOs решение, т.к. мне пока это не интересно, то я просто закрыл это окно. В итоге создается решение содержащее 4 проекта:
Как не сложно догадаться, три из них под платформы, ну и первое в списке, это разделяемая сборка код из которой будет использоваться в остальных решениях.
Следующим шагом я выгрузил проект с iOs приложением, запустил билд и получил ошибку Could not find android.jar for API Level 26. This means the Android SDK platform for API Level 26 is not installed. Either install it in the Android SDK Manager (Tools > Open Android SDK Manager...), or change your Xamarin.Android project to target an API version that is installed.
В принципе, все логично, т.к. я устанавливал SDK для Android версии 7.1.1, а ей соответствует 25 версия. Заходим в настройки Android проекта и меняем версию:
Все, можно запускать UWP и Android приложение. Эмулятор по прежнему долго грузиться, но мы уже можем убедиться, что приложения работают и показываю жизнеутверждающий текст про "Добро пожаловать...".
Как я уже сказал, это не очень интересно, поэтому добавлю заголовок в приложение и главное меню "Гамбургкер".
Создаем в корневом проекте папки Views и ViewModels. В папку ViewModels добавляем класс MenuViewModel, в папку Views добавляем Content Page для самого меню и две Content Page для показа как работают переходы (Home и Second):
На вьюхах Home и Second я просто поменял текст:
Как я уже сказал, они нужны только для того, чтобы было понятно на какой мы странице.
Меняем нашу главную страницу, делая ее потомком MasterDetailPage. Для этого меняем предка в cs файле и удалив все содержимое, меняем корневой тег. Вот такой получается XAML:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Adjutant"
             x:Class="Adjutant.MainPage">

</MasterDetailPage>
И вот так cs:

Начинаем реализовывать меню. Для этого нам нужно знать, на какой мы странице сейчас находимся. Для упрощения примера, я не буду усложнять с правильной реализацией навигации и просто добавлю в класс App три свойства (для хранения ссылки на главное окно, для хранения ссылки которая сейчас показывается и признак развернутости меню):
public partial class App : Application
{

    public staticNavigationPage NavigationPage { get; private set; }
    private static MainPage RootPage;
    public static bool MenuIsPresented
    {
        get
        {
            return RootPage.IsPresented;
        }
        set
        {
            RootPage.IsPresented = value;
        }

    }
В ViewModel добавляем следующий код:
public class MenuViewModel
{
    public ICommand GoHomeCommand { get; set; }
    public ICommand GoSecondCommand { get; set; }

    public MenuViewModel()
    {
        GoHomeCommand = newCommand(GoHome);
        GoSecondCommand = newCommand(GoSecond);
    }

    void GoHome(object obj)
    {
        App.NavigationPage.Navigation.PopToRootAsync();
        App.MenuIsPresented = false;
    }

    void GoSecond(object obj)
    {
        App.NavigationPage.Navigation.PushAsync(new SecondView());
        App.MenuIsPresented = false;
    }

}
Как видно, у нас просто две команды. Одна для перехода на домашнюю страницу, вторая для перехода на вторую.
Самое интересное. Вьюха с меню. В XAML добавляем две кнопки:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Adjutant.Views.MenuView">
    <ContentPage.Content>
        <StackLayout BackgroundColor="Gray">
            <Button Text="Домой" TextColor="White" BackgroundColor="Green" Command="{Binding GoHomeCommand}" />
            <Button Text="Вторая страница" TextColor="White" BackgroundColor="Navy" Command="{Binding GoSecondCommand}" />
        </StackLayout>
    </ContentPage.Content>

</ContentPage>
А в cs, опять же, чтобы не усложнять пример, добавим создание ViewModel:
public partial class MenuView : ContentPage
{
    public MenuView()
    {
        BindingContext = newMenuViewModel();
        Title = "Menu";
        InitializeComponent();
    }

}
Осталось только поправить создание приложения. Дописываем конструктор класса App:
public App()
{
    InitializeComponent();
    var menuPage = new MenuView();
    NavigationPage = newNavigationPage(new HomeView());
    RootPage = new MainPage();
    RootPage.Master = menuPage;
    RootPage.Detail = NavigationPage;
    MainPage = RootPage;

}
Запускаем. Вот так это выглядит в эмуляторе после запуска:
А вот так после тапа на "гамбургере":
При переходе на вторую страницу меню пропадает и заменяется стрелкой назад:
В целом все нормально ровно до тех пор, пока не запустим UWP:
Нет "гамбургера", меню показывается всегда... Вот такие они, Xmarin.Forms - одинаковые на всех платформах :)
Ладно, в следующий раз поговорим о моделях навигации.

[Xamarin] 2. Собираем приложения и делаем главное меню "Гамбургер"

Продолжаем разговор, т.к. собрать приложения это достаточно просто, то кроме этого добавим в приложение меню "Гамбургер". Поехали.

Создаем новый проект в студии выбрав Cross Platform App (Xamarin):
В открывшемся окне я оставил пустое приложение, но вот шаринг кода выбрал на основе PLC. Принципиальная разница в том, как организуется доступ к платформозависимым вещам. В Shared Project, это директива #if.
После нажатия на принять и некоторого времени (если вы это делаете в первый раз, то выскочит предупреждение, что надо бы операционную систему перевести в режим разработчика, плюс выскочит окошко подключения к устройству на котором компилировать iOs решение, т.к. мне пока это не интересно, то я просто закрыл это окно. В итоге создается решение содержащее 4 проекта:
Как не сложно догадаться, три из них под платформы, ну и первое в списке, это разделяемая сборка код из которой будет использоваться в остальных решениях.
Следующим шагом я выгрузил проект с iOs приложением, запустил билд и получил ошибку Could not find android.jar for API Level 26. This means the Android SDK platform for API Level 26 is not installed. Either install it in the Android SDK Manager (Tools > Open Android SDK Manager...), or change your Xamarin.Android project to target an API version that is installed.
В принципе, все логично, т.к. я устанавливал SDK для Android версии 7.1.1, а ей соответствует 25 версия. Заходим в настройки Android проекта и меняем версию:
Все, можно запускать UWP и Android приложение. Эмулятор по прежнему долго грузиться, но мы уже можем убедиться, что приложения работают и показываю жизнеутверждающий текст про "Добро пожаловать...".
Как я уже сказал, это не очень интересно, поэтому добавлю заголовок в приложение и главное меню "Гамбургкер".
Создаем в корневом проекте папки Views и ViewModels. В папку ViewModels добавляем класс MenuViewModel, в папку Views добавляем Content Page для самого меню и две Content Page для показа как работают переходы (Home и Second):
На вьюхах Home и Second я просто поменял текст:
Как я уже сказал, они нужны только для того, чтобы было понятно на какой мы странице.
Меняем нашу главную страницу, делая ее потомком MasterDetailPage. Для этого меняем предка в cs файле и удалив все содержимое, меняем корневой тег. Вот такой получается XAML:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Adjutant"
             x:Class="Adjutant.MainPage">

</MasterDetailPage>
И вот так cs:

Начинаем реализовывать меню. Для этого нам нужно знать, на какой мы странице сейчас находимся. Для упрощения примера, я не буду усложнять с правильной реализацией навигации и просто добавлю в класс App три свойства (для хранения ссылки на главное окно, для хранения ссылки которая сейчас показывается и признак развернутости меню):
public partial class App : Application
{

    public staticNavigationPage NavigationPage { get; private set; }
    private static MainPage RootPage;
    public static bool MenuIsPresented
    {
        get
        {
            return RootPage.IsPresented;
        }
        set
        {
            RootPage.IsPresented = value;
        }

    }
В ViewModel добавляем следующий код:
public class MenuViewModel
{
    public ICommand GoHomeCommand { get; set; }
    public ICommand GoSecondCommand { get; set; }

    public MenuViewModel()
    {
        GoHomeCommand = newCommand(GoHome);
        GoSecondCommand = newCommand(GoSecond);
    }

    void GoHome(object obj)
    {
        App.NavigationPage.Navigation.PopToRootAsync();
        App.MenuIsPresented = false;
    }

    void GoSecond(object obj)
    {
        App.NavigationPage.Navigation.PushAsync(new SecondView());
        App.MenuIsPresented = false;
    }

}
Как видно, у нас просто две команды. Одна для перехода на домашнюю страницу, вторая для перехода на вторую.
Самое интересное. Вьюха с меню. В XAML добавляем две кнопки:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Adjutant.Views.MenuView">
    <ContentPage.Content>
        <StackLayout BackgroundColor="Gray">
            <Button Text="Домой" TextColor="White" BackgroundColor="Green" Command="{Binding GoHomeCommand}" />
            <Button Text="Вторая страница" TextColor="White" BackgroundColor="Navy" Command="{Binding GoSecondCommand}" />
        </StackLayout>
    </ContentPage.Content>

</ContentPage>
А в cs, опять же, чтобы не усложнять пример, добавим создание ViewModel:
public partial class MenuView : ContentPage
{
    public MenuView()
    {
        BindingContext = newMenuViewModel();
        Title = "Menu";
        InitializeComponent();
    }

}
Осталось только поправить создание приложения. Дописываем конструктор класса App:
public App()
{
    InitializeComponent();
    var menuPage = new MenuView();
    NavigationPage = newNavigationPage(new HomeView());
    RootPage = new MainPage();
    RootPage.Master = menuPage;
    RootPage.Detail = NavigationPage;
    MainPage = RootPage;

}
Запускаем. Вот так это выглядит в эмуляторе после запуска:
А вот так после тапа на "гамбургере":
При переходе на вторую страницу меню пропадает и заменяется стрелкой назад:
В целом все нормально ровно до тех пор, пока не запустим UWP:
Нет "гамбургера", меню показывается всегда... Вот такие они, Xmarin.Forms - одинаковые на всех платформах :)
Ладно, в следующий раз поговорим о моделях навигации.

[Xamarin] 1. Готовим среду

Есть идейка несложного приложения которое должно работать на Android и Windows Desctop. В нем не будет ничего выходящего за классические контролы ввода, поэтому для его реализации решил попробовать Xamarin. Заодно и на реальном, пусть  и небольшом, проекте поиграюсь с новой для меня технологией. О том что делаю и как постараюсь написать циклом статей. А то большинство информации по Xamarin на английском, а то что есть на русском или рассказывает какой он крутой или почему он не крутой.
Первая статья о том, что надо установить и настроить, чтобы эта вся штука завелась. Если у кого-то кто будет пытаться это повторить возникнут проблемы, скажите, поправлю доку.


Для разработки я планирую использовать Visual Studio 2017. Поэтому первое что сделал, в Visual Studio Installer поставил галку:
После установки дополнительных компонентов, запускаем студию и проверяем, что SDK установилось корректно. Настройки Xamarin-а для Android можно открыть в главном меню Tools > Options и в дереве перейти в узел Xamarin > Android Settings. Для тех кто не любит долго кликать мышкой  и прокручивать списки есть быстрый путь. Нажимаем Ctrl+Q, набираем "xama" и в открывшемся списке или выбираем клавиатурой или мышкой тот же пункт:

Сами настройки выглядят так (если SDK установлены не по пути по умолчанию, необходимо указать правильные папки):
Осталось только настроить интеграцию с железкой и запуск в эмуляторе. В моем понимании нужны оба варианта. С железкой вопросов нет, не проверив на устройстве быть уверенным что все работает ожидаемо - невозможно. Ну а эмулятор позволяет заниматься быстрыми операциями - посмотреть как выглядит, по быстрому отладить что-от не работающее и т.д.
Настройка эмулятора идет в два этапа, сначала нам надо убедиться, что у нас установлен HAXL (аппаратное ускорение эмулятора). Для этого запускаем Tools > Android > Android Emulator Manager. И в нем один из эмуляторов. В процессе запуска должно появиться вот такое сообщение:

Если при запуске строка "HAX is working and emulator runs in fast virt mode" присутствует, то все ок, аппаратное ускорение есть. Если там ошибки или еще что, то можно посмотреть здесь (у меня все заработало сразу, поэтому не перевожу).
Второй этап, надо добавить виртуалку с целевой версией Android. Т.к. у меня устройство с Android 7.1.1, а продвигать предложение я не планирую, то буду ставить только этот образ. Для этого запускаем Tools > Android > Android SDK Manager и выбираем нужные образы:
Возвращаемся в Android Emulator Manager и создаем новое устройство:
Все, можно запускать:
Единственно, т.к. я использовал не x86 образ, то запускается он очень долго...
Осталось подключить устройство на Android. Для этого привычно идем в Android SDK Manager и устанавливаем USB Driver (если не установлен):
На телефоне заходим в Настройки > О телефоне. Тут зависит от версии Android. В каких то надо тапать по версии билда Android, в каких-то (как у меня) на версии MUI. После этого включается режим разработчика. В настройках включаем отладку по USB и установку по USB. После подключения устройства у меня Windows сама определила драйвер, если у вам устройство не определяется (в менеджере устройств находится во вкладке "Другие устройства"), то надо обновить драйвер указав что он находится по пути: [Android SDK install path]\extras\google\usb_driver (У меня это C:\Program Files (x86)\Android\android-sdk\extras\google\usb_driver).
На этом все. Эмуляторы и физическое устройство доступны для загрузки приложения и отладки в Visual Studio:
Подготовлено по материалам официального руководства.

[Xamarin] 1. Готовим среду

Есть идейка несложного приложения которое должно работать на Android и Windows Desctop. В нем не будет ничего выходящего за классические контролы ввода, поэтому для его реализации решил попробовать Xamarin. Заодно и на реальном, пусть  и небольшом, проекте поиграюсь с новой для меня технологией. О том что делаю и как постараюсь написать циклом статей. А то большинство информации по Xamarin на английском, а то что есть на русском или рассказывает какой он крутой или почему он не крутой.
Первая статья о том, что надо установить и настроить, чтобы эта вся штука завелась. Если у кого-то кто будет пытаться это повторить возникнут проблемы, скажите, поправлю доку.


Для разработки я планирую использовать Visual Studio 2017. Поэтому первое что сделал, в Visual Studio Installer поставил галку:
После установки дополнительных компонентов, запускаем студию и проверяем, что SDK установилось корректно. Настройки Xamarin-а для Android можно открыть в главном меню Tools > Options и в дереве перейти в узел Xamarin > Android Settings. Для тех кто не любит долго кликать мышкой  и прокручивать списки есть быстрый путь. Нажимаем Ctrl+Q, набираем "xama" и в открывшемся списке или выбираем клавиатурой или мышкой тот же пункт:

Сами настройки выглядят так (если SDK установлены не по пути по умолчанию, необходимо указать правильные папки):
Осталось только настроить интеграцию с железкой и запуск в эмуляторе. В моем понимании нужны оба варианта. С железкой вопросов нет, не проверив на устройстве быть уверенным что все работает ожидаемо - невозможно. Ну а эмулятор позволяет заниматься быстрыми операциями - посмотреть как выглядит, по быстрому отладить что-от не работающее и т.д.
Настройка эмулятора идет в два этапа, сначала нам надо убедиться, что у нас установлен HAXL (аппаратное ускорение эмулятора). Для этого запускаем Tools > Android > Android Emulator Manager. И в нем один из эмуляторов. В процессе запуска должно появиться вот такое сообщение:

Если при запуске строка "HAX is working and emulator runs in fast virt mode" присутствует, то все ок, аппаратное ускорение есть. Если там ошибки или еще что, то можно посмотреть здесь (у меня все заработало сразу, поэтому не перевожу).
Второй этап, надо добавить виртуалку с целевой версией Android. Т.к. у меня устройство с Android 7.1.1, а продвигать предложение я не планирую, то буду ставить только этот образ. Для этого запускаем Tools > Android > Android SDK Manager и выбираем нужные образы:
Возвращаемся в Android Emulator Manager и создаем новое устройство:
Все, можно запускать:
Единственно, т.к. я использовал не x86 образ, то запускается он очень долго...
Осталось подключить устройство на Android. Для этого привычно идем в Android SDK Manager и устанавливаем USB Driver (если не установлен):
На телефоне заходим в Настройки > О телефоне. Тут зависит от версии Android. В каких то надо тапать по версии билда Android, в каких-то (как у меня) на версии MUI. После этого включается режим разработчика. В настройках включаем отладку по USB и установку по USB. После подключения устройства у меня Windows сама определила драйвер, если у вам устройство не определяется (в менеджере устройств находится во вкладке "Другие устройства"), то надо обновить драйвер указав что он находится по пути: [Android SDK install path]\extras\google\usb_driver (У меня это C:\Program Files (x86)\Android\android-sdk\extras\google\usb_driver).
На этом все. Эмуляторы и физическое устройство доступны для загрузки приложения и отладки в Visual Studio:
Подготовлено по материалам официального руководства.

[Xamarin] 1. Готовим среду

Есть идейка несложного приложения которое должно работать на Android и Windows Desctop. В нем не будет ничего выходящего за классические контролы ввода, поэтому для его реализации решил попробовать Xamarin. Заодно и на реальном, пусть  и небольшом, проекте поиграюсь с новой для меня технологией. О том что делаю и как постараюсь написать циклом статей. А то большинство информации по Xamarin на английском, а то что есть на русском или рассказывает какой он крутой или почему он не крутой.
Первая статья о том, что надо установить и настроить, чтобы эта вся штука завелась. Если у кого-то кто будет пытаться это повторить возникнут проблемы, скажите, поправлю доку.


Для разработки я планирую использовать Visual Studio 2017. Поэтому первое что сделал, в Visual Studio Installer поставил галку:
После установки дополнительных компонентов, запускаем студию и проверяем, что SDK установилось корректно. Настройки Xamarin-а для Android можно открыть в главном меню Tools > Options и в дереве перейти в узел Xamarin > Android Settings. Для тех кто не любит долго кликать мышкой  и прокручивать списки есть быстрый путь. Нажимаем Ctrl+Q, набираем "xama" и в открывшемся списке или выбираем клавиатурой или мышкой тот же пункт:

Сами настройки выглядят так (если SDK установлены не по пути по умолчанию, необходимо указать правильные папки):
Осталось только настроить интеграцию с железкой и запуск в эмуляторе. В моем понимании нужны оба варианта. С железкой вопросов нет, не проверив на устройстве быть уверенным что все работает ожидаемо - невозможно. Ну а эмулятор позволяет заниматься быстрыми операциями - посмотреть как выглядит, по быстрому отладить что-от не работающее и т.д.
Настройка эмулятора идет в два этапа, сначала нам надо убедиться, что у нас установлен HAXL (аппаратное ускорение эмулятора). Для этого запускаем Tools > Android > Android Emulator Manager. И в нем один из эмуляторов. В процессе запуска должно появиться вот такое сообщение:

Если при запуске строка "HAX is working and emulator runs in fast virt mode" присутствует, то все ок, аппаратное ускорение есть. Если там ошибки или еще что, то можно посмотреть здесь (у меня все заработало сразу, поэтому не перевожу).
Второй этап, надо добавить виртуалку с целевой версией Android. Т.к. у меня устройство с Android 7.1.1, а продвигать предложение я не планирую, то буду ставить только этот образ. Для этого запускаем Tools > Android > Android SDK Manager и выбираем нужные образы:
Возвращаемся в Android Emulator Manager и создаем новое устройство:
Все, можно запускать:
Единственно, т.к. я использовал не x86 образ, то запускается он очень долго...
Осталось подключить устройство на Android. Для этого привычно идем в Android SDK Manager и устанавливаем USB Driver (если не установлен):
На телефоне заходим в Настройки > О телефоне. Тут зависит от версии Android. В каких то надо тапать по версии билда Android, в каких-то (как у меня) на версии MUI. После этого включается режим разработчика. В настройках включаем отладку по USB и установку по USB. После подключения устройства у меня Windows сама определила драйвер, если у вам устройство не определяется (в менеджере устройств находится во вкладке "Другие устройства"), то надо обновить драйвер указав что он находится по пути: [Android SDK install path]\extras\google\usb_driver (У меня это C:\Program Files (x86)\Android\android-sdk\extras\google\usb_driver).
На этом все. Эмуляторы и физическое устройство доступны для загрузки приложения и отладки в Visual Studio:
Подготовлено по материалам официального руководства.

Получение имени метода вызвавшего текущий метод

В C# 6 появилось новое ключевое слово nameof которое позволяет получить строку с именем члена класса, что позволяет существенно упростить написание, например, реализации INotifyPropertyChanged. Зачем он нужен я писал вот здесь. Под катом, я покажу как упростить вызов метода OnPropertyChanged. Ну и покажу какой замечательный атрибут появился в .Net Framework 4.5 благодаря которому, даже nameof больше не нужно.

Итак, немного напомню. У нас есть некоторый класс реализующий упомянутый интерфейс. В интерфейсе объявлено всего одно событие и нам нужно при изменении значений свойств его вызывать. Такой класс может иметь вид:


public class MyClass : INotifyPropertyChanged
{
    private string _myString;

    public string MyString
    {
        get
        {
            return _myString;
        }
        set
        {
            if (value != _myString)
            {
                _myString = value;
                OnPropertyChanged(nameof(MyString));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string p_propertyName)
    {
        PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(p_propertyName));
    }
}

Как видно, при вызове метода OnProeprtyChanged мы вынуждены передавать строку. Что может привести к тому, что свойство мы переименуем, через рефакторинг изменение распространиться везде кроме этой строки и об изменении свойства никто не узнает.
Решить эту проблему можно применением нового ключевого слова nameof , вот так:


public string MyString
{
    get
    {
        return _myString;
    }
    set
    {
        if (value != _myString)
        {
            _myString = value;
            OnPropertyChanged(nameof(MyString));
        }
    }
}

Но и это еще не все. С появлением атрибута [CallerMemberName], у нас есть возможность вообще ничего не передавать в этот метод, он сам будет узнавать имя члена класса который его вызвал:


public class MyClass : INotifyPropertyChanged
{
    private string _myString;
 
    public string MyString
    {
        get
        {
            return _myString;
        }
        set
        {
            if (value != _myString)
            {
                _myString = value;
                OnPropertyChanged();
            }
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected void OnPropertyChanged([CallerMemberNamestring p_propertyName = "")
    {
        PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(p_propertyName));
    }
}

Стало намного лучше.

Получение имени метода вызвавшего текущий метод

В C# 6 появилось новое ключевое слово nameof которое позволяет получить строку с именем члена класса, что позволяет существенно упростить написание, например, реализации INotifyPropertyChanged. Зачем он нужен я писал вот здесь. Под катом, я покажу как упростить вызов метода OnPropertyChanged. Ну и покажу какой замечательный атрибут появился в .Net Framework 4.5 благодаря которому, даже nameof больше не нужно.

Итак, немного напомню. У нас есть некоторый класс реализующий упомянутый интерфейс. В интерфейсе объявлено всего одно событие и нам нужно при изменении значений свойств его вызывать. Такой класс может иметь вид:


public class MyClass : INotifyPropertyChanged
{
    private string _myString;

    public string MyString
    {
        get
        {
            return _myString;
        }
        set
        {
            if (value != _myString)
            {
                _myString = value;
                OnPropertyChanged(nameof(MyString));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string p_propertyName)
    {
        PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(p_propertyName));
    }
}

Как видно, при вызове метода OnProeprtyChanged мы вынуждены передавать строку. Что может привести к тому, что свойство мы переименуем, через рефакторинг изменение распространиться везде кроме этой строки и об изменении свойства никто не узнает.
Решить эту проблему можно применением нового ключевого слова nameof , вот так:


public string MyString
{
    get
    {
        return _myString;
    }
    set
    {
        if (value != _myString)
        {
            _myString = value;
            OnPropertyChanged(nameof(MyString));
        }
    }
}

Но и это еще не все. С появлением атрибута [CallerMemberName], у нас есть возможность вообще ничего не передавать в этот метод, он сам будет узнавать имя члена класса который его вызвал:


public class MyClass : INotifyPropertyChanged
{
    private string _myString;
 
    public string MyString
    {
        get
        {
            return _myString;
        }
        set
        {
            if (value != _myString)
            {
                _myString = value;
                OnPropertyChanged();
            }
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected void OnPropertyChanged([CallerMemberNamestring p_propertyName = "")
    {
        PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(p_propertyName));
    }
}

Стало намного лучше.

Поддержка C# 6.0 на Build Server

Столкнулся с проблемкой, что при создании Build Definition для нового проекта билд падает со странной ошибкой вида:
ExtensionExceptionExtension.cs (22, 0)
Unexpected character '$'
Как выяснилось, на TFS сервере нет студии 2015 и не умеет он билдить C# 6.0.
Под катом как полечить.

1. На машину где установлен билд агент ставим Microsoft Build Tools 2015.
2. На машину где установлен билд агент ставим Microsoft .NET Framework 4.5.2 Developer Pack.
3. Перезагружаем машину где стоит билд агент.
4. В настройках Build Definition указываем атрибут для MSBuild: /tv:14.0

Все работает.