【问题标题】:Can I set the color of a button inside a Xamarin.Forms ListView programmatically?我可以以编程方式设置 Xamarin.Forms ListView 中按钮的颜色吗?
【发布时间】:2019-10-24 03:10:05
【问题描述】:

我有一个 ListView,其中有一个在 ViewCell 中定义的按钮。我想知道如何以编程方式更新此按钮的颜色。

这就是我的 ListView 在 XAML 中的定义方式。

<ListView x:Name="HeaderListView">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*"/>
                                        <RowDefinition Height="*"/>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Label Text="{Binding Title}" TextColor="Black"/>
                                    <Button x:Name="DetailButton" Grid.Row="1"
                                            BackgroundColor="Blue"
                                            TextColor="White"
                                            Text="Details"
                                            Clicked="DetailButton_Clicked"/>
                                </Grid>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

数据源是我用C#设置的SQLite数据库:

protected override void OnAppearing()
        {
            base.OnAppearing();

            using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation))
            {
                conn.CreateTable<Header>();
                var header = conn.Query<Header>("select * from Header");
                HeaderListView.ItemsSource = header;
            }
        }

Detail 按钮选择它所在的行,并导航到使用所选行的 Header 数据构建的 DetailPage。 DetailPage 包含第二个 ListView,这是一个 Detail 表,它通过外键链接到 Header 表。 Detail 表上的每一行都有一个布尔属性Complete。 DetailPage的ListView的ItemsSource的设置方法和HeaderListView一样。

一些示例代码来反映我的表格的样子:

public class Header
    {
        public int HeaderId { get; set; } // The primary key of the Header table
        public string Code { get; set; } // Foreign key of the Detail table

        // various Header data
        public string Data1 { get; set; }
        public DateTime Data2 { get; set; }
        public int Data3 { get; set; }
    }

public class Detail
    {
        public int DetailId { get; set; } // Primary key of Detail table
        public string Code { get; set; } // Foreign key; Many Detail rows to one Header row

        // various Detail data
        public string Detail1 { get; set; }
        public int Detail2 { get; set; }
        public TimeSpan Detail3 { get; set; }
        public bool Complete { get; set; }
    }

HeaderListView 上我的详细信息按钮的期望行为如下:

1) BackgroundColor="Blue" 当 Header 没有匹配的 Detail 行时,因此 DetailPage ListView 中没有项目。

2) BackgroundColor="Orange" 当 Header 至少有一个匹配的 Detail 行(因此在 DetailPage ListView 中至少有一个项目),并且 any 行的 Complete 属性设置为 @ 987654329@.

3) BackgroundColor="Green" 当 DetailPage 至少有一个匹配的行,并且 所有 它的“行”Complete 属性设置为 true。如果只有一行与 Header 匹配且其 Complete 属性为 true,则 Detail 按钮仍为绿色。

请不要对自定义工具提出建议,除非绝对无法使用默认 Xamarin 工具执行此操作。

【问题讨论】:

    标签: c# xaml listview xamarin xamarin.forms


    【解决方案1】:

    在您的 xaml 中,您应该将绑定设置为按钮的 backgroundColor:

    <Button  BackgroundColor="{Binding btnColor}"/>
    

    并且在后面的代码中,在你的header的不同情况下将值设置为btnColor

    protected override void OnAppearing()
    {
        base.OnAppearing();
    
        var header = conn.Query<Header>("select * from Header");
    
        for (int i = 0; i < header.Count; i++)
        {
            Header h = header[i];
    
            if (Header has no matching Detail rows)
            {
             h.btnColor = Color.Blue;
            }
            else if (your condition)
            {
                h.btnColor = Color.Orange;
            }
            else if (your condition) {
                h.btnColor = Color.Green
            }
            else
            {
                h.btnColor = defaultColor;
            }
        }
    
        HeaderListView.ItemsSource = header;
    }
    

    在模型中添加 btnColor 属性:

    public class Header
    {
        public int HeaderId { get; set; } // The primary key of the Header table
        public string Code { get; set; } // Foreign key of the Detail table
    
        // various Header data
         public Color btnColor { get; set; }
    
    }
    

    【讨论】:

    • 这完全符合我的要求,谢谢!给未来任何人的注意事项,将btnColor 属性存储为字符串而不是颜色,因为 SQLite 不接受颜色类型的列。我根本不需要使用转换器,只需将 BackgroundColor 绑定到字符串属性就可以了,但以防万一我找到了用于构建字符串到颜色转换器的教程:forums.xamarin.com/discussion/37751/…
    • 当颜色依赖于 sqlite 中找到的数据时,为什么还要将颜色存储在 sqlite 中?这没有任何意义。
    【解决方案2】:

    您可以在 xaml 中使用带有触发器的样式。

    您的视图模型可能具有返回颜色/样式以供列使用的 getter,然后您可以将列颜色绑定到该颜色/样式。

    或者您可以通过基于datagrid.columns[0].BackgroundColor = new SolidBrush("blue"); 或类似的数据分配标题背景颜色以编程方式完成。

    【讨论】:

    【解决方案3】:

    IIRC,我之前给你一个类似问题的类似答案。您应该再次在 ViewModel 中创建一个 ViewModel。

    public HeaderViewModel : BindableObject {
        public Header Header { get; set; }
    
        private ObservableCollection<Detail> details { get; set; }
        public ObservableCollection<Detail> Details { 
            get => details;
            set {
                details = value;
                OnPropertyChanged();
                OnPropertyChanged(nameof(ButtonBackgroundColor);
            }
        }
    
        public Color ButtonBackgroundColor {
            get {
                if (Details.Count == 0) return Color.Blue;
                if (Details.Any(d => !d.Complete) return Color.Orange;
                return Color.Green;
            }
        }
    
        public HeaderViewModel(Header header) {
            this.Header = header;
            this.Details = SelectAllDetailItemsForWithThisHeaderId() //Your query that does what the name tells
        }
    }
    

    然后在你的主视图模型中,为每个 Header 项创建一个 HeaderViewModel 实例,将它们放入 ObservableCollection 中,并将它们绑定为 ListView 的 ItemsSource:

    public class ViewModel : INotifyPropertyChanged {
        private ObservableCollection<HeaderViewModel> headers { get; set; }
        public ObservableCollection<HeaderViewModel> Headers {
            get => headers;
            set {
                headers = value;
                OnPropertyChanged();
            }
        }
    
        //constructor
        public ViewModel() {
            List<Header> queriedHeaders = new List<Header>();
    
            //please fetch data inside your viewmodel btw, currently you do it inside the view.
            using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation))
            {
                conn.CreateTable<Header>();
                queriedHeaders = conn.Query<Header>("select * from Header").ToList();
            }
    
            List<HeaderViewModel> _headers = new List<HeaderViewModel>();
            foreach(Header h in queriedHeaders) {
                var hvm = new HeaderViewModel(h);
                _headers.Add(hvm);
            }
    
            this.Headers = new ObservableCollection<HeaderViewModel>(_headers);
        }
    }
    

    然后在上面的 XAML 示例中,像这样更改两个标签:

    &lt;ListView ItemsSource="{Binding Headers}"&gt;

    &lt;Button BackgroundColor="{Binding ButtonBackgroundColor}"&gt;

    【讨论】:

      猜你喜欢
      • 2023-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-06
      • 2010-12-21
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      相关资源
      最近更新 更多