0
votes

My question is about how to control the background and text color of multiple buttons when you read a button click in MVVM. To make my question a bit clear please have a look at the UI I have attached.

UI1

I have already implemented this on code behind i.e on button click, I am handling all of the buttons separately. The original background and text color are white and black respectively and when you click on any other button except 1W that button will be highlighted. In the next image, 3M is clicked

UI2

            lbl3M.BackgroundColor = Color.FromHex(defaultColor);
            lbl3M.TextColor = Color.White;
            if (lbl1M.BackgroundColor != Color.White)
            {
                lbl1M.BackgroundColor = Color.White;
                lbl1M.TextColor = Color.Black;
            }
            if (lbl1W.BackgroundColor != Color.White)
            {
                lbl1W.BackgroundColor = Color.White;
                lbl1W.TextColor = Color.Black;
            }
            if (lbl6M.BackgroundColor != Color.White)
            {
                lbl6M.BackgroundColor = Color.White;
                lbl6M.TextColor = Color.Black;
            }
            if (lbl1Y.BackgroundColor != Color.White)
            {
                lbl1Y.BackgroundColor = Color.White;
                lbl1Y.TextColor = Color.Black;
            }

I have done this on each button clicked.

I know this approach is not cost-effective and I want to learn how to implement in MVVM way

EDIT: I have created a function which reset all the buttons to Original UI and change the UI on button clicked

 void ResetButtonUI()
    {
        lbl1W.BackgroundColor = Color.White;
        lbl1W.TextColor = Color.Black;
        lbl1M.BackgroundColor = Color.White;
        lbl1M.TextColor = Color.Black;
        lbl3M.BackgroundColor = Color.White;
        lbl3M.TextColor = Color.Black;
        lbl6M.BackgroundColor = Color.White;
        lbl6M.TextColor = Color.Black;
        lbl1Y.BackgroundColor = Color.White;
        lbl1Y.TextColor = Color.Black;
    }

and on each button i have this logic

         ResetButtonUI();
         button.BackgroundColor = Color.FromHex(defaultColor);
         button.TextColor = Color.White;
2
You should learn how to do it in an effective way and then you should know how to do it in MVVM.Sir Rufo
Try to understand what you really want to do. All of that color game is only presentation of some logic. That logic should happen in the ViewModel and the presentation of the result stays in the View.Sir Rufo
I have implemented with different logic. Check out my edit. Can you give me advice if this can be an efficient approach to implement?A for android
Try with a Converter and bind some kind of IsSelected boolean property to the button to handle color change logic. I think you should have a command for each button, so you can handle there the IsSelected logic for both new selected button and previous one. Try with this approachFabriBertani

2 Answers

1
votes

Compared with listview, CollectionView is more suitable for your needs. Listview is more complicated to place horizontally.

Here is running GIF. enter image description here

Here is code.

     <CollectionView ItemsSource="{Binding Persons}" HeightRequest="50" SelectionMode="Single" SelectionChanged="CollectionView_SelectionChanged_1" >
            <CollectionView.ItemsLayout>
                <LinearItemsLayout   Orientation="Horizontal" />
            </CollectionView.ItemsLayout>
            <CollectionView.ItemTemplate>
                <DataTemplate>


                    <StackLayout HorizontalOptions="Center"  VerticalOptions="Center" >
                        <Label Text="{Binding FirstName}" FontSize="20"  Margin="20,10,20,0"/>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

Background code.

   BindingContext = new HomepageViewModel();

public List Persons { get; set; }

    public HomepageViewModel() {

        Persons = new List<Person>();
        Persons.Add(new Person() { FirstName = "1W" });
        Persons.Add(new Person() { FirstName = "1M" });
        Persons.Add(new Person() { FirstName = "3M" });
        Persons.Add(new Person() { FirstName = "6M" });
        Persons.Add(new Person() { FirstName = "1Y" });
    }

} If you want to change the selectItem color, here is a link about it. https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/selection#change-selected-item-color

0
votes

So there are 5 options and the user have to choose one of them.

The ViewModel must contain 2 properties:

  • Collection of all options
  • Selected option

It should look like this

// ReactiveObject is from ReactiveUI => https://reactiveui.net/
public class MainViewModel : ReactiveObject
{
    private readonly ObservableCollection<TimeSpanItem> _options;
    private TimeSpanItem _selectedOption;

    public ReadOnlyObservableCollection<TimeSpanItem> Options { get; }

    public TimeSpanItem SelectedOption { get => _selectedOption; set => this.RaiseAndSetIfChanged( ref _selectedOption, value ); }

    public MainViewModel()
    {
        _options = new ObservableCollection<TimeSpanItem>();
        Options = new ReadOnlyObservableCollection<TimeSpanItem>( _options );

        _options.Add( new TimeSpanItem( 1, TimeSpanKind.Week ) );
        _options.Add( new TimeSpanItem( 1, TimeSpanKind.Month ) );
        _options.Add( new TimeSpanItem( 3, TimeSpanKind.Month ) );
        _options.Add( new TimeSpanItem( 6, TimeSpanKind.Month ) );
        _options.Add( new TimeSpanItem( 1, TimeSpanKind.Year ) );

        SelectedOption = _options.Last();
    }
}

and some data types:

public enum TimeSpanKind
{
    M = 2,
    W = 1,
    Y = 3,

    Week = W,
    Month = M,
    Year = Y,
}

public class TimeSpanItem
{
    public TimeSpanItem( int value, TimeSpanKind kind )
    {
        Value = value;
        Kind = kind;
    }

    public int Value { get; }
    public TimeSpanKind Kind { get; }

    public override string ToString()
    {
        return $"{Value}{Kind}";
    }
}

Now it is time for the presentation. The easiest way to present a selectable collection is a ListBox or ListView because everything can be wired up in XAML

<Window
      x:Class="WpfApp1.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="clr-namespace:WpfApp1"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      Title="MainWindow"
      Width="800"
      Height="450"
      mc:Ignorable="d">
<Window.DataContext>
  <local:MainViewModel/>
</Window.DataContext>
    <Grid>

        <ListBox
              HorizontalAlignment="Center"
              VerticalAlignment="Center"
              ItemsSource="{Binding Items}"
              SelectedItem="{Binding SelectedItem}">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel
                          Margin="5"
                          Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock
                          MinWidth="40"
                          Margin="5"
                          Text="{Binding}"
                          TextAlignment="Center" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

    </Grid>
</Window>

and that is the result enter image description here