• Какое оформление предпочтительнее?

    FoggyFinder
    @FoggyFinder
    Общие замечания (ко всем кусочкам):

    Нет разделения на функции (проблема: дублирование кода, усложняет восприятие)

    Вынесите каждую часть в удобный метод и вызывайте. Например:
    * Получение числа с консоли
    * Поиск минимального из трех чисел
    * Проверка на четность

    Вам будет намного понятнее что выполняет код - ваш взгляд охватит несколько вызовов и не будет отвлекаться на конкретные детали реализации.

    Общие проблемы закончились, теперь сверху вниз:

    1 кусок:

    1. [ Критично ] Нет проверки на корректность ввода. Пользователь может случайно ввести букву и метод Convert.ToInt32 выбросит исключение. Довольно неприятно.

    2. Нарушение соглашения об именовании для переменной FinalResult

    3. Необязательная инициализация переменной FinalResult при объявлении.

    4. [ Субъективно ] Проблемы с форматированием: тернарный оператор занимает слишком много места для одной строки

    5. [ Может рассматриваться как придирка ] Копипаст подход. Вывод сообщения можно вынести из if-ов в - он одинаков для всех случаев.

    2 кусок:

    1. [ Критично ] Аналогично предыдущему

    2. Нарушение соглашения об именования для переменной MuchSmaller

    3. Объявление и лишняя инициализация переменной MuchSmaller намного впереди реального использования.

    4. Слишком сложные условные выражения.

    5. Аналогично п.5 предыдущего примера.

    3 кусок:

    Здесь, ура!, нет основной проблемы которая встречается во всех остальных примерах.

    1. Нарушение соглашения об именовании для переменной Result

    2. Странная смесь английского и русского языка в информационных сообщениях

    3. Странная смесь использования интернирования строк ($) и старого форматирования.

    4 кусок:

    1. [ Критично ] Нет проверки на корректность ввода. Пользователь может случайно ввести букву и метод Convert.ToInt32 выбросит исключение. Довольно неприятно.

    2. [ Существенно ] Копипаст подход для проверки на четность.

    3. Избыточные скобки в switch case

    5 кусок:

    1. [ Критично ] Нет проверки на корректность ввода. Пользователь может случайно ввести букву и метод Parse выбросит исключение.

    2. Проблемы с названием переменных. inputOne

    Итого:

    3-ий вариант условно нормальный. Остальные хуже.

    Упражнение:

    Попробуйте написать свой вариант с учетом замечаний перечисленных выше =)
    Ответ написан
    Комментировать
  • Найти минимальный элемент из максимальных элементов каждой строки двумерного массива?

    FoggyFinder
    @FoggyFinder
    Вы не уточнили какой способ ввода данных, поэтому для демонстрации воспользуемся стандартным классом Random для генерации псевдослучайных чисел.

    Для поиска значения в последовательности можно использовать:

    Max - для максимального.

    Min - для минимального.

    const int n = 5;
    const int m = 5;
    
    const int max = 10;
    
    var rand = new Random();
    
    var array = new int[n][];
    for (int i = 0; i < n; i++)
    {
        array[i] = new int[m];
        for (int j = 0; j < m; j++)
            array[i][j] = rand.Next(max + 1);
    }
    
    Console.WriteLine("Массив = ");
    foreach (var row in array)
    {
        foreach (var value in row)
            Console.Write($"{value,4}");
        Console.WriteLine();
    }
    
    var min = array.Min(row => row.Max());
    Console.WriteLine($"Минимальный элемент из максимальных каждой строки = {min}");


    По хорошему код нужно разбить на функции, но эту часть оставлю вам.
    Ответ написан
    1 комментарий
  • Можно ли во ViewModel узнать ширину элемента View?

    FoggyFinder
    @FoggyFinder
    Зависит от того зачем вам нужна информация о размерах UI - элементов.

    Если это часть пользовательских настроек, то хранить их на уровне ViewModel совершенно нормально и никак не противоречит паттерну.

    Но если это нужно исключительно для временной настройки UI, то и код должен находится на уровне View.

    Для вашего примера решение будет таким: добавьте обработчик события клика на кнопку и выводить информацию там.

    MVVM это не означает что в code-behind не должно быть никакого кода. Это типичная ошибка. В .xaml.cs не должно быть того, что не относится непосредственно к отображению.

    Управление анимацией, вывод вспомогательных сообщений, кастомизация пользовательских элементов управления - все это может быть там.
    Ответ написан
    Комментировать
  • Какой язык выбрать (F# или Lisp)?

    FoggyFinder
    @FoggyFinder
    Смело выбирайте F#. Коротко о преимуществах:

    1. Это не экзотика (да, его реально используют).

    2. Дружелюбное сообщество, в том числе русскоязычное:

    3. F# язык из семейства dotnet. Эта платформа, несмотря на свою популярность, открывает новые горизонты с плавным переходом к .NET Core.

    4. F# оптимальный выбор для тех кто только начинает свой путь по дороге функциональной парадигмой. Одной из причин является то, что F# не чисто функциональный, а в первую очередь функциональный. Таким образом освоив базовые возможности F# вам будет значительно легче понять код на Haskell или Erlang.

    Теперь к недостаткам:

    1. Познакомившись с F# вам, вероятно, больше не захочется использовать ничего другого. Да, он настолько хорош.

    2. Далеко не все F# конструкции оперативно поддерживаются. Вы можете столкнутся с необходимостью писать не идиоматичный F# код при работе с UWP или Xamarin.Forms.
    Ответ написан
    Комментировать
  • Xamarin.Forms Как в функцию передать значение кнопки?

    FoggyFinder
    @FoggyFinder
    Лучше всего будет начать с чтения туториалов по MVVM

    Паттерн Model-View-ViewModel

    Ключевое в таком подходе разделение представления (View) от внутренней логики (Model/VM). В некоторых очень простых случаях (например, демонстрационных примерах) роли Model и VM объединяют в одну.

    Концептуально, то что вы описали в своем вопросе можно определить следующим образом:

    Есть некоторый объект, который содержит информацию об изменяемом значении. Также объект характеризуется двумя состояниями: "нажат" (кнопка окрашена в красный цвет) и "отжат" (кнопка стандартного цвета). В терминах C# можно выразить в виде класса:

    public class Item : ViewModelBase
    {
        private int value;
        private bool isSelected;
        public int Value
        {
            get => value;
            private set => SetProperty(ref this.value, value);
        }
        public bool IsSelected
        {
            get => isSelected;
            set => SetProperty(ref isSelected, value);
        }
    
        public Item(int value, bool isSelected = false)
        {
            Value = value;
            IsSelected = isSelected;
        }
    
        public void IncrementSelected()
        {
            if (IsSelected)
            {
                Value++;
            }
        }
    }


    Обратите внимание что класс унаследован от ViewModelBase это вспомогательный класс для того чтобы сообщать представлению об изменении некоторых свойств объекта.

    Теперь сама страница:

    Здесь у вас есть 3 объекта (Item) которые можно изменять, а также методы для изменения этих самых объектов. Понадобятся всего два метода:

    1. Изменить состояние соответствующего объекта по нажатию на кнопку
    2. Изменить значение для всех объектов для которых IsSelected истинно

    Опишем этом в коде:

    public class MyContext
    {
        public int BaseValue { get; } = 14;
        public Item Item1 { get; }
        public Item Item2 { get; }
        public Item Item3 { get; }
    
        public MyContext()
        {
            Item1 = new Item(BaseValue, true);
            Item2 = new Item(BaseValue);
            Item3 = new Item(BaseValue);
    
            IncrementSelectedCommand =
                new DelegateCommand<object>(_ => IncrementSelected());
            ClickCommand = new DelegateCommand<Item>(
                o => SelectOrDeselect(o),
                o => o is Item);
        }
    
        public ICommand IncrementSelectedCommand { get; }
        public ICommand ClickCommand { get; }
    
        public void IncrementSelected()
        {
            Item1.IncrementSelected();
            Item2.IncrementSelected();
            Item3.IncrementSelected();
        }
    
        public void SelectOrDeselect(Item item)
        {
            item.IsSelected = !item.IsSelected;
        }
    }


    Теперь сама сложная часть - View. Сложная она только тем что я хочу максимально близко оставить вашу разметку.

    Для начала определим простой стиль который будет менять цвет фона у кнопки:

    <Style x:Key="selectableBtn" TargetType="Button">
        <Style.Triggers>
            <DataTrigger
                Binding="{Binding IsSelected}"
                TargetType="Button"
                Value="True">
                <Setter Property="BackgroundColor" Value="Red" />
            </DataTrigger>
        </Style.Triggers>
    </Style>


    Пока все просто - как только IsSelected становится равным True задаем установку свойства BackgroundColor в нужный цвет.

    Последний рубеж - сетка:

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Label
            Grid.Column="1"
            FontSize="Large"
            HorizontalTextAlignment="Center"
            Text="I"
            VerticalTextAlignment="Center" />
        <Label
            Grid.Column="2"
            FontSize="Large"
            HorizontalTextAlignment="Center"
            Text="II"
            VerticalTextAlignment="Center" />
        <Label
            Grid.Column="3"
            FontSize="Large"
            HorizontalTextAlignment="Center"
            Text="III"
            VerticalTextAlignment="Center" />
        <Label
            Grid.Row="1"
            FontSize="Medium"
            HorizontalTextAlignment="Center"
            Text="{Binding BaseValue}" />
        <Button
            Grid.Row="1"
            Grid.Column="1"
            BindingContext="{Binding Item1}"
            Command="{Binding BindingContext.ClickCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type d:ContentPage}}}"
            CommandParameter="{Binding .}"
            Style="{StaticResource selectableBtn}"
            Text="{Binding Value}" />
        <Button
            Grid.Row="1"
            Grid.Column="2"
            BindingContext="{Binding Item2}"
            Command="{Binding BindingContext.ClickCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type d:ContentPage}}}"
            CommandParameter="{Binding .}"
            Style="{StaticResource selectableBtn}"
            Text="{Binding Value}" />
        <Button
            Grid.Row="1"
            Grid.Column="3"
            BindingContext="{Binding Item3}"
            Command="{Binding BindingContext.ClickCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type d:ContentPage}}}"
            CommandParameter="{Binding .}"
            Style="{StaticResource selectableBtn}"
            Text="{Binding Value}" />
        <Button
            Grid.Row="2"
            Grid.Column="3"
            Command="{Binding IncrementSelectedCommand}"
            Text="Add" />
    </Grid>


    Единственную хитрость здесь представляет установка BindingContext для кнопки чтобы реагировать на связанный элемент.

    И как вам уже подсказали чтобы из View передать информацию в VM можно использовать CommandParameter.

    И, завершающий штрих, установка BindingContext для содержимого:

    this.BindingContext = new MyContext();

    код выше можно поместить в конструктор для MainPage

    Напоследок, демонстрация работоспособности

    5f22d822d81b2087880445.gif

    Я намеренно не приводил код для классов ViewModelBase и RelayCommand - это стандартный классы реализации которых вы легко сможете найти.
    Например, тут и тут.
    Ответ написан
    1 комментарий