1+ using System . ComponentModel ;
2+
3+ namespace Maui . Controls . Sample . Issues ;
4+
5+ [ Issue ( IssueTracker . Github , 31897 , "CollectionView card height appears larger in Developer Balance sample" , PlatformAffected . iOS | PlatformAffected . macOS ) ]
6+ public class Issue31897 : ContentPage
7+ {
8+ Button getHeight ;
9+ Button addItemsButton ;
10+ Button removeItemsButton ;
11+ Button updateNewItemsButton ;
12+ Label HeightLabel ;
13+ Label ItemCountLabel ;
14+ CollectionView2 ProjectsCollectionView ;
15+ Issue31897ViewModel viewModel ;
16+
17+ public Issue31897 ( )
18+ {
19+ var mainGrid = new Grid ( ) ;
20+
21+ var scrollView = new ScrollView ( ) ;
22+
23+ // Create the inner grid with padding and row spacing
24+ var innerGrid = new Grid
25+ {
26+ Padding = new Thickness ( 10 ) ,
27+ RowSpacing = 10
28+ } ;
29+
30+ // Add row definitions
31+ innerGrid . RowDefinitions . Add ( new RowDefinition { Height = GridLength . Auto } ) ; // Controls row
32+ innerGrid . RowDefinitions . Add ( new RowDefinition { Height = GridLength . Auto } ) ; // Height label
33+ innerGrid . RowDefinitions . Add ( new RowDefinition { Height = GridLength . Auto } ) ; // Item count label
34+ innerGrid . RowDefinitions . Add ( new RowDefinition { Height = GridLength . Auto } ) ; // CollectionView
35+
36+ // Create a horizontal stack for control buttons
37+ var controlsStack = new HorizontalStackLayout
38+ {
39+ Spacing = 10
40+ } ;
41+
42+ // Create the "Get CV Height" button
43+ getHeight = new Button
44+ {
45+ Text = "Get CV Height" ,
46+ AutomationId = "GetHeightButton"
47+ } ;
48+
49+ getHeight . Clicked += ( object sender , EventArgs e ) =>
50+ {
51+ HeightLabel . Text = Math . Round ( ProjectsCollectionView . Height ) . ToString ( ) ;
52+ } ;
53+
54+ // Create the "Add Items" button
55+ addItemsButton = new Button
56+ {
57+ Text = "Add Items" ,
58+ AutomationId = "AddItemsButton"
59+ } ;
60+
61+ addItemsButton . Clicked += ( object sender , EventArgs e ) =>
62+ {
63+ viewModel . AddItems ( 1 ) ; // Add 1 item
64+ UpdateItemCount ( ) ;
65+ } ;
66+
67+ // Create the "Remove Items" button
68+ removeItemsButton = new Button
69+ {
70+ Text = "Remove Items" ,
71+ AutomationId = "RemoveItemsButton"
72+ } ;
73+
74+ removeItemsButton . Clicked += ( object sender , EventArgs e ) =>
75+ {
76+ viewModel . RemoveItems ( 2 ) ; // Remove 2 items
77+ UpdateItemCount ( ) ;
78+ } ;
79+
80+ // Create the "Update New Items" button
81+ updateNewItemsButton = new Button
82+ {
83+ Text = "Update New" ,
84+ AutomationId = "UpdateNewItemsButton"
85+ } ;
86+
87+ updateNewItemsButton . Clicked += ( object sender , EventArgs e ) =>
88+ {
89+ viewModel . UpdateWithNewItems ( ) ;
90+ UpdateItemCount ( ) ;
91+ } ;
92+
93+ // Add buttons to horizontal stack
94+ controlsStack . Children . Add ( getHeight ) ;
95+ controlsStack . Children . Add ( addItemsButton ) ;
96+ controlsStack . Children . Add ( removeItemsButton ) ;
97+ controlsStack . Children . Add ( updateNewItemsButton ) ;
98+
99+ getHeight . SetValue ( SemanticProperties . HeadingLevelProperty , SemanticHeadingLevel . Level1 ) ;
100+ Grid . SetRow ( controlsStack , 0 ) ;
101+
102+ // Create the height label
103+ HeightLabel = new Label ( ) ;
104+ HeightLabel . AutomationId = "HeightLabel" ;
105+ HeightLabel . SetValue ( SemanticProperties . HeadingLevelProperty , SemanticHeadingLevel . Level1 ) ;
106+ Grid . SetRow ( HeightLabel , 1 ) ;
107+
108+ // Create the item count label
109+ ItemCountLabel = new Label
110+ {
111+ AutomationId = "ItemCountLabel" ,
112+ Text = "Items: 0"
113+ } ;
114+ ItemCountLabel . SetValue ( SemanticProperties . HeadingLevelProperty , SemanticHeadingLevel . Level1 ) ;
115+ Grid . SetRow ( ItemCountLabel , 2 ) ;
116+
117+ // Create the CollectionView
118+ ProjectsCollectionView = new CollectionView2
119+ {
120+ Margin = new Thickness ( - 7.5 , 0 ) ,
121+ MinimumHeightRequest = 250 ,
122+ SelectionMode = SelectionMode . Single
123+ } ;
124+
125+ // Set up the ItemsLayout
126+ ProjectsCollectionView . ItemsLayout = new LinearItemsLayout ( ItemsLayoutOrientation . Horizontal )
127+ {
128+ ItemSpacing = 7.5
129+ } ;
130+
131+ // Create the DataTemplate for items
132+ var itemTemplate = new DataTemplate ( ( ) =>
133+ {
134+ var border = new Border
135+ {
136+ WidthRequest = 200 ,
137+ Background = Colors . GreenYellow
138+ } ;
139+
140+ var contentView = new ContentView ( ) ;
141+
142+ var verticalStackLayout = new VerticalStackLayout
143+ {
144+ Spacing = 15 ,
145+ Background = Colors . Red ,
146+ VerticalOptions = LayoutOptions . Start
147+ } ;
148+
149+ // Name label
150+ var nameLabel = new Label
151+ {
152+ TextColor = Colors . Gray ,
153+ FontSize = 14 ,
154+ TextTransform = TextTransform . Uppercase
155+ } ;
156+ nameLabel . SetBinding ( Label . TextProperty , "Name" ) ;
157+
158+ // Description label
159+ var descriptionLabel = new Label
160+ {
161+ LineBreakMode = LineBreakMode . WordWrap
162+ } ;
163+ descriptionLabel . SetBinding ( Label . TextProperty , "Description" ) ;
164+
165+ verticalStackLayout . Children . Add ( nameLabel ) ;
166+ verticalStackLayout . Children . Add ( descriptionLabel ) ;
167+ contentView . Content = verticalStackLayout ;
168+ border . Content = contentView ;
169+
170+ return border ;
171+ } ) ;
172+
173+ ProjectsCollectionView . ItemTemplate = itemTemplate ;
174+
175+ // Set up data binding
176+ viewModel = new Issue31897ViewModel ( ) ;
177+ BindingContext = viewModel ;
178+ ProjectsCollectionView . SetBinding ( CollectionView . ItemsSourceProperty , "Projects" ) ;
179+
180+ Grid . SetRow ( ProjectsCollectionView , 3 ) ;
181+
182+ // Add all controls to the inner grid
183+ innerGrid . Children . Add ( controlsStack ) ;
184+ innerGrid . Children . Add ( HeightLabel ) ;
185+ innerGrid . Children . Add ( ItemCountLabel ) ;
186+ innerGrid . Children . Add ( ProjectsCollectionView ) ;
187+
188+ // Set up the hierarchy
189+ scrollView . Content = innerGrid ;
190+ mainGrid . Children . Add ( scrollView ) ;
191+ Content = mainGrid ;
192+
193+ // Initialize item count display
194+ UpdateItemCount ( ) ;
195+ }
196+
197+ void UpdateItemCount ( )
198+ {
199+ ItemCountLabel . Text = $ "Items: { viewModel . Projects . Count } ";
200+ }
201+
202+ public class Issue31897ViewModel : INotifyPropertyChanged
203+ {
204+ List < Issue31897Project > _projects = new ( ) ;
205+ int _nextId = 0 ;
206+
207+ public event PropertyChangedEventHandler PropertyChanged ;
208+
209+ protected virtual void OnPropertyChanged ( string propertyName )
210+ {
211+ PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
212+ }
213+
214+ public List < Issue31897Project > Projects
215+ {
216+ get { return _projects ; }
217+ set
218+ {
219+ _projects = value ;
220+ OnPropertyChanged ( nameof ( Projects ) ) ;
221+ }
222+ }
223+
224+ public Issue31897ViewModel ( )
225+ {
226+ LoadData ( ) ;
227+ }
228+
229+ void LoadData ( )
230+ {
231+ var projects = new List < Issue31897Project > ( ) ;
232+ for ( int i = 0 ; i < 4 ; i ++ )
233+ {
234+ projects . Add ( new Issue31897Project
235+ {
236+ ID = i ,
237+ Name = "Developer balance card view " + ( i + 1 ) ,
238+ Description = "This is a sample description for project " + ( i + 1 )
239+ } ) ;
240+ _nextId = i + 1 ;
241+ }
242+
243+ Projects = projects ;
244+ }
245+
246+ public void AddItems ( int count )
247+ {
248+ var currentProjects = new List < Issue31897Project > ( _projects ) ;
249+
250+ for ( int i = 0 ; i < count ; i ++ )
251+ {
252+ currentProjects . Add ( new Issue31897Project
253+ {
254+ ID = _nextId ,
255+ Name = "Added card view " + ( _nextId + 1 ) ,
256+ Description = "This is a dynamically added description for project " + ( _nextId + 1 )
257+ } ) ;
258+ _nextId ++ ;
259+ }
260+
261+ Projects = currentProjects ;
262+ }
263+
264+ public void RemoveItems ( int count )
265+ {
266+ var currentProjects = new List < Issue31897Project > ( _projects ) ;
267+
268+ int itemsToRemove = Math . Min ( count , currentProjects . Count ) ;
269+ for ( int i = 0 ; i < itemsToRemove ; i ++ )
270+ {
271+ if ( currentProjects . Count > 0 )
272+ {
273+ currentProjects . RemoveAt ( currentProjects . Count - 1 ) ;
274+ }
275+ }
276+
277+ if ( currentProjects . Count == 0 )
278+ {
279+ _nextId = 0 ; // Reset ID counter if all items are removed
280+ }
281+
282+ Projects = currentProjects ;
283+ }
284+
285+ public void ClearItems ( )
286+ {
287+ Projects = new List < Issue31897Project > ( ) ;
288+ }
289+
290+ public void UpdateWithNewItems ( )
291+ {
292+ var projects = new List < Issue31897Project > ( ) ;
293+ for ( int i = 0 ; i < 6 ; i ++ )
294+ {
295+ projects . Add ( new Issue31897Project
296+ {
297+ ID = i + 500 ,
298+ Name = "New updated item " + ( i + 1 ) ,
299+ Description = "This is a completely new item set with fresh content " + ( i + 1 )
300+ } ) ;
301+ }
302+ Projects = projects ;
303+ }
304+ }
305+
306+ public class Issue31897Project
307+ {
308+ public int ID { get ; set ; }
309+ public string Name { get ; set ; } = string . Empty ;
310+ public string Description { get ; set ; } = string . Empty ;
311+ }
312+ }
0 commit comments