Ответы пользователя по тегу Xamarin
  • В ListView не отображаются данные из ObservableCollection и XAML отказывается делать Binding. Как исправить?

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

    Adding x:DataType to a ContentPage breaks nested o...

    Так что чтобы исправить проблему достаточно просто добавить

    x:DataType="vm:MedicineViewModel"

    чтобы было понятнее привожу контекст

    <ListView.ItemTemplate>
        <DataTemplate x:DataType="vm:MedicineViewModel">
            <ViewCell>
                <ViewCell.View>
                    <StackLayout>
                        <Label FontSize="Large" Text="{Binding Title}" />
                        <Label FontSize="Small" Text="{Binding Format}" />
                        <Label FontSize="Small" Text="{Binding Method}" />
                    </StackLayout>
                </ViewCell.View>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>


    И позвольте дать пару советов которые не относятся непосредственно к ответу

    1. В процессе работы над проектов время от времени запрашивайте CodeReview, так код будет чище и вы сможете "расти" быстрее.

    2. Не отправляйте в гит секретные ключи. Пока проект учебный это не так и страшно, но лучше проявлять осмотрительность как можно раньше.

    3. Когда сталкиваетесь с проблемой (а такое всенепременно будет) не тащите в вопрос код из своего проекта, лучше создайте маленький тестовый проект где не будет ничего лишнего. На первый взгляд это лишняя трата времени, но во многих случаях вы докопаетесь до сути проблемы во время подготовки такого MCVE.
    Ответ написан
    4 комментария
  • 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 комментарий
  • Проблемы с NETStandard.Library в Xamarin?

    FoggyFinder
    @FoggyFinder
    В списке источников NuGet:

    Tools -> NuGet Package Manager -> Package Manager Settings -> Package Sources.

    должен находится стандартный:

    https://api.nuget.org/v3/index.json


    Если его там нет, то нужно будет добавить.
    Ответ написан
    Комментировать
  • Не запускается таймер c# (xamarin), что не так?

    FoggyFinder
    @FoggyFinder
    В Xamarin.Forms можно использовать Device.StartTimer
    Ответ написан
    Комментировать