Xamarin.Forms 将自定义控件创建为网格布局中的一行

Posted

技术标签:

【中文标题】Xamarin.Forms 将自定义控件创建为网格布局中的一行【英文标题】:Xamarin.Forms create a custom control as a row in a Grid layout 【发布时间】:2019-08-16 11:47:18 【问题描述】:

假设我有一个显示为网格布局的项目列表。每个项目占一行,由一列中的多个项目组成。它基本上是一张桌子:

<Grid>
 <Label Text="Item1" Grid.Row="0" Grid.Colum="0" />
 <Image Src="something1" Grid.Row="0" Grid.Colum="1" />

 <Label Text="Item2" Grid.Row="1" Grid.Colum="0" />
 <Image Src="something2" Grid.Row="1" Grid.Colum="1" />

 <Label Text="Item3" Grid.Row="2" Grid.Colum="0" />
 <Image Src="something3" Grid.Row="2" Grid.Colum="1" />
</Grid>

每个标签/图像代表我要显示的项目列表中的一行。我暂时不担心数据绑定,我只想将标签/图像移动到自定义控件中,以便可以使用该自定义控件将“行”添加到我的网格中:

<Grid>
 <customcontrol:MyCustomRowControl Text="Item1" Source="img1" Grid.Row="0"/>
 <customcontrol:MyCustomRowControl Text="Item2" Source="img1" Grid.Row="1"/>
 <customcontrol:MyCustomRowControl Text="Item3" Source="img1" Grid.Row="3"/>
</Grid>

我可能可以将自定义控件中的标签/图像/等设置为代码隐藏中的适当行/列。我迷失的是我应该制作这个自定义控件的基类类型是什么?因为将成为 Grid 内容的是该类,而不是 Labels 和 Images,因此 Grid.Row 和 Grid.Column 不会正确传播。我真的希望我设法解释了这一点。

我可以在 Xamarin 中创建一个自定义控件,我可以将它作为内容添加到 Grid 并让它的子项尊重 Grid 的列吗?

【问题讨论】:

如果我理解正确,您可以将其设为具有两列的 Grid,第 0 列是 Label,第 1 列是 Image。然后使用 customcontrol 和 ColumnSpan=2 嗯,是的,这将编译,但列不会在项目之间均衡。每个标签都有自己的宽度,所以表格基本上会被破坏 您是否希望所有标签的宽度都为最宽的Label?否则,您可以使用固定宽度(* 而不是 ColumnDefinitions 中的 Auto) 是的,我在 Auto 上有一些列,我希望这些列宽在所有行上传播,本质上是创建一个表 你能测试我的代码吗? @Radu094 【参考方案1】:

你可以这样写

DynamicGridView 类

public class DynamicGridView : Grid

        private int _rowCount;
        private int _columnCount;
        protected int _column;
        protected int _starHeight = 0;
        protected int _type;
        protected int[] _starHeightList;

        public DynamicGridEnum _dynamicGridEnum;

        public DynamicGridView(DynamicGridEnum dynamicGridEnum, params int[] starHeightList)
        
            _type = 2;
            switch (dynamicGridEnum)
            
                case DynamicGridEnum.Auto:
                    _column = starHeightList[0];
                    break;
                case DynamicGridEnum.Star:
                    _column = starHeightList[0];
                    _starHeight = starHeightList[1];
                    _type = 1;
                    break;
                case DynamicGridEnum.Custom:
                    _column = starHeightList.Length;
                    break;
                default:
                    break;
            
            _starHeightList = starHeightList;
            _dynamicGridEnum = dynamicGridEnum;
            _rowCount = 0;
            _columnCount = 0;
            Padding = 0;
            Margin = 0;
            ColumnSpacing = -1;
            RowSpacing = -1;
        

        public virtual void AddView(View view)
        
            int countRow = _rowCount / _column;
            if (RowDefinitions.Count <= countRow)
            
                RowDefinitions.Add(new RowDefinition()  Height = new GridLength(1, (GridUnitType)_type) );
            
            Children.Add(view, _columnCount, countRow);
            _rowCount++;
            _columnCount++;
            _columnCount = _columnCount % _column;
        

DynamicGrid 类

public class DynamicGrid : DynamicGridView

        public DynamicGrid(DynamicGridEnum dynamicGridEnum, params int[] starHeightList) : base(dynamicGridEnum, starHeightList)
        
            for (int i = 0; i < starHeightList.Length; i++)  starHeightList[i] = starHeightList[i] <= 0 ? 1 : starHeightList[i]; 

            if (dynamicGridEnum == DynamicGridEnum.Custom)
            
                StartCustomGrid();
            
            else
                StartGrid();
        

        private void StartGrid()
        
            int percent = 100 / _column;
            for (int i = 0; i < _column; i++)
                ColumnDefinitions.Add(new ColumnDefinition()  Width = new GridLength(percent, (GridUnitType)_type) );
        

        private void StartCustomGrid()
        
            foreach (var item in _starHeightList)
                ColumnDefinitions.Add(new ColumnDefinition()  Width = new GridLength(item, GridUnitType.Star) );
        

以及动态网格的使用(我为网格类型定义了一个枚举。对于 例如,如果枚举是自动的,它将自动调整网格的行/列。)

public partial class MainPage : ContentPage

public MainPage()

   StackLayout sl = new StackLayout();
   DynamicGrid dynamicGrid = new DynamicGrid(Enums.DynamicGridEnum.Custom, 20, 50, 20, 0);
   dynamicGrid.AddView(new BoxView()  BackgroundColor = Color.AliceBlue );
   dynamicGrid.AddView(new BoxView()  BackgroundColor = Color.Aqua );
   dynamicGrid.AddView(new BoxView()  BackgroundColor = Color.AntiqueWhite );
   dynamicGrid.AddView(new BoxView()  BackgroundColor = Color.Azure );
   sl.Children.Add(new CardView(Color.Beige, Color.Bisque, 60, Color.Black, 90, 10));
   sl.Children.Add(dynamicGrid);
   Content = sl;


【讨论】:

以上是关于Xamarin.Forms 将自定义控件创建为网格布局中的一行的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个自定义控件,用户可以在 Xamarin.Forms 中添加任何类型的视图?

自定义控件的 Xamarin 数据绑定值计算为 Xamarin.Forms.Binding

Xamarin.Forms自定义用户界面控件实现一个HybridWebView(混合webview)

在父项中设置绑定时,Xamarin.Forms 绑定到自定义控件不起作用

C# 自定义控件(圆形进度条) Xamarin Forms

ReactiveUI 中的 Xamarin.Forms 控件是不是需要自定义绑定?