locked
How to change the color of frame in code using an ItemTemplate in Code RRS feed

  • Question

  • User399635 posted

    Hello, I'm fairly new to Xamarin and am trying to add a feature that changes the color of a frame based on whether a ticket was valid or not, however I've ran into difficulties trying to make it change dynamically. I've created my listView in ItemTemplates in Code, and when I try doing a binding of string label with error codes, upon trying to access the value using statusLabel.GetValue(Label.TextProperty).ToString(); I get a null exception, even though when the application runs, the text does show up.

    I've tried multiple things, including iterating over the children of the listview, but I can't seem to change the value because it is configured in the ItemTemplate. I also tried creating a method within my template class that would change the color value, but nothing has worked up to now.

    If I remove the "statusLabel.GetValue(Label.TextProperty).ToString()" calls, the app runs and displays the initial black color used to initiate the statusColor variable, but I don´t want them to be black, but rather change color based on the content of the statusLabel or some other way.

    Any suggestions would be greatly appreciated, here is my code thus far: and thank you in advance.

    ``` //Gets the tickets and adds them to the listview private Task RefreshListBookedTickets()
    {

            System.Collections.Generic.List<TextCellItem> ticketList = new MenuData(); 
    
            return new Task(() =>
            {
                try
                {
                    var tickets = Helper.ReauthIfNecessary(() => App.GetRecentTickets(App.Bearer));
    
                    Device.BeginInvokeOnMainThread(delegate
                    {
                        foreach (Ticket ticket in tickets)
                        {
                            string status = RefreshStatus(ticket);
                            //Color statusColor = getStatusColor(ticket);
                            //App.Logger.Debug("RefreshListBookedTickets - Ticket Status:" + statusColor.ToString());
    
                            ticketList.Add(new TextCellItem
                            {
                                dateText = ticket.StartTime.ToString("MMM dd, yy"),
                                timeText = ticket.StartTime.ToString("HH:mm"),
                                cityText = StaticZoneInfo.getZoneNameFromID(ticket.MandantId.ToString()),
                                durationText = "   Min: " + ticket.Duration,
                                ticketStatus = status
                                //ticketColor = statusColor
    
                            }) ;
                        }
    
            // Create stacklayout with listview
                        var content = new StackLayout
                        {
                            Margin = new Thickness(20),
                            Children = {
                                 new Label { Text = "My tickets", FontSize = 14, TextColor= Color.Black,  },
                                 new ListView { IsPullToRefreshEnabled = true, ItemTemplate = new DataTemplate(typeof(ListTicketView)), ItemsSource = ticketList,               Margin = new Thickness(0, 20, 0, 0) }
                            }
                        };
    
                        MainGrid.Children.Add(content, 0, 1);
    
                    });
                }
                catch (ApiException e)
                {
                    App.Logger.Error("BookingPage - RefreshBookedTickets - API Exception(" + e.ErrorCode + "): " +
                                     e.ErrorContent);
                }
                catch (Exception e)
                {
                    App.Logger.Error("BookingPage - RefreshBookedTickets - Exception: " + e);
                }
            });
        }
    
    //gets the string code value
        private String RefreshStatus(Ticket ticket)
        {
            if (ticket.Error != null || ticket.Error != Ticket.ErrorEnum.NONE)
            {
                return "Error";
            }
    
            if (!ticket.DeliveryConfirmed)
            {
                return "Pending";
            }
    
            if (ticket.EndTime > DateTime.Now)
            {
                return "Valid";
            }
    
            return "Void";
        }
    
    //The itemTemplate
        private class ListTicketView:ViewCell  
        {
    
            public static Color StatusColor { get; set; }
    
            public ListTicketView()
            {           
                var grid = new Grid();
                var statusLabel = new Label();
    
                statusLabel.SetBinding(Label.TextProperty, "ticketStatus");
    
                StatusColor = Color.Black;
    
                if (statusLabel.GetValue(Label.TextProperty).ToString() == "Valid")         // <-- Causes Null Exception
                {
                    statusColor = Color.Green;
                }
                else if (statusLabel.GetValue(Label.TextProperty).ToString() == "Error")    // <-- Causes Null Exception
                {
                    statusColor = Color.Red;
                }
                var frame = new Frame
                {
                    HeightRequest = 40,
                    WidthRequest = 40,
                    CornerRadius = 20,
                    VerticalOptions = LayoutOptions.Start,
                    HorizontalOptions = LayoutOptions.Start,
                    BackgroundColor = StatusColor,
                    Margin = new Thickness(10, 0, 0, 0),
                    Padding = 0
                };
                var dateLabel = new Label 
                { 
                    FontAttributes = FontAttributes.Bold,
                    FontSize = 17,
                    TextColor = Color.Black,
                    Margin = new Thickness (-20,0,0,0)
                };
                var timeLabel = new Label
                {
                    FontAttributes = FontAttributes.None,
                    FontSize = 14,
                    TextColor = Color.Black,
                    Margin = new Thickness(-20, 0, 0, 0)
    
                };
                var cityLabel = new Label
                {
                    FontSize = 17,
                    TextColor = Color.Black,
                    HorizontalOptions = LayoutOptions.Center,
    
    
                };
                var durationLabel = new Label
                {
                    FontAttributes = FontAttributes.None,
                    FontSize = 17,
                    TextColor = Color.Black,
                    HorizontalTextAlignment = TextAlignment.Center };
    
                dateLabel.SetBinding(Label.TextProperty, "dateText");
                timeLabel.SetBinding(Label.TextProperty, "timeText");
                cityLabel.SetBinding(Label.TextProperty, "cityText");
                durationLabel.SetBinding(Label.TextProperty, "durationText");
    
    
                grid.Children.Add(frame);
                Grid.SetRowSpan(frame, 2);
                grid.Children.Add(dateLabel, 1, 0);
                grid.Children.Add(timeLabel, 1, 1);
                grid.Children.Add(cityLabel, 2, 0);
                grid.Children.Add(durationLabel, 3, 0);
    
                View = grid;
            }
    
        }
    
        private class TextCellItem
        {
            public string ticketStatus { get; set; }
            public string dateText { get; set; }
            public string timeText { get; set; }
            public string cityText { get; set; }
            public string durationText { get; set; }
        }
    
        private class MenuData : List<TextCellItem>
        {
            public MenuData()
            {
            }
        }
    

    ```

    Wednesday, February 24, 2021 3:08 PM

Answers

  • User379860 posted

    changes the color of a frame based on whether a ticket was valid or not,I've ran into difficulties trying to make it change >dynamically.

    If you want to change it dynamically, you should use MVVM to achieve it, in your TextCellItem to achieve INotifyPropertyChanged, then add a property called BackgroundColor, then you can bind the BackgroundColor in your Label. Then you can change it in your viewModel dynamically.

    ``` private Color _backgroundColor;

        public Color BackgroundColor
        {
            get { return _backgroundColor; }
            set
            {
                _backgroundColor = value;
    
                OnPropertyChanged("BackgroundColor");
    
            }
        }
    
        public void SetColors(bool isSelected)
        {
            if (isSelected)
            {
                BackgroundColor = Color.FromRgb(0.20, 0.20, 1.0);
            }
            else
            {
                BackgroundColor = Color.FromRgb(0.95, 0.95, 0.95);
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    

    ```

    ```

    ```

    And I do not suggest you to use background code to develop code, you should use XAML, it will be faster. If you do not know how to learn it, you can refer to the following link.

    https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/converters#binding-converter-properties

    https://www.c-sharpcorner.com/article/learn-about-data-binding-in-xamarin-forms/


    Xamarin forums are migrating to a new home on Microsoft Q&A! We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A! For more information, please refer to this sticky post.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Thursday, February 25, 2021 8:15 AM

All replies

  • User379860 posted

    changes the color of a frame based on whether a ticket was valid or not,I've ran into difficulties trying to make it change >dynamically.

    If you want to change it dynamically, you should use MVVM to achieve it, in your TextCellItem to achieve INotifyPropertyChanged, then add a property called BackgroundColor, then you can bind the BackgroundColor in your Label. Then you can change it in your viewModel dynamically.

    ``` private Color _backgroundColor;

        public Color BackgroundColor
        {
            get { return _backgroundColor; }
            set
            {
                _backgroundColor = value;
    
                OnPropertyChanged("BackgroundColor");
    
            }
        }
    
        public void SetColors(bool isSelected)
        {
            if (isSelected)
            {
                BackgroundColor = Color.FromRgb(0.20, 0.20, 1.0);
            }
            else
            {
                BackgroundColor = Color.FromRgb(0.95, 0.95, 0.95);
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    

    ```

    ```

    ```

    And I do not suggest you to use background code to develop code, you should use XAML, it will be faster. If you do not know how to learn it, you can refer to the following link.

    https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/converters#binding-converter-properties

    https://www.c-sharpcorner.com/article/learn-about-data-binding-in-xamarin-forms/


    Xamarin forums are migrating to a new home on Microsoft Q&A! We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A! For more information, please refer to this sticky post.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Thursday, February 25, 2021 8:15 AM
  • User399635 posted

    @LeonLu , Thank you very much for your response and help. I initially tried doing this in XAML, but did not manage to get what I wanted working, and doing it with code-behind I did, so I stuck to it. But I realize that it's more of a headache that way, I will do a refactoring to switch to XAML and follow your recommendations.

    To be honest, I'm still having some issues wrapping my head around a correct implementation of MVVM, but I'm following some more in depth tutorials regarding the matter, so hopefully that will get resolved soon.

    Once again, thanks!

    Thursday, February 25, 2021 8:41 AM