Я обновляю приложение с Xamarin до Мауи. Форма с ListView, которая раньше работала идеально, теперь не принимает ввод в элементах управления «Ввод» или «Редактор», а кнопки не работают, ЕСЛИ элемент не является 1-м или 2-м элементом в списке !!! (ребята, вы не можете это выдумать!).
В форме есть кнопка для добавления еще одного элемента в коллекцию. Эта коллекция, привязанная к представлению списка. Каждый элемент имеет несколько полей для ввода данных (2 элемента управления вводом, 1 элемент управления редактором), а также кнопку.
Если список пуст, я могу добавить 1 элемент, затем добавить еще один. Все работает нормально. Если я добавлю третий (или более), элементы управления в этих элементах списка не примут входные данные. (!)
Мой XAML выглядит так (я немного упростил его для ясности):
<ContentPage.Content>
<StackLayout Orientation = "Vertical" VerticalOptions = "StartAndExpand">
<Button WidthRequest = "200" HeightRequest = "50" Text = "Add New" HorizontalOptions = "Center" Clicked = "NewCommentClicked"/>
<BoxView HeightRequest = "10" />
<StackLayout Orientation = "Vertical" VerticalOptions = "StartAndExpand" HeightRequest = "1200">
<ListView x:Name = "CommentsList"
ItemsSource = "{Binding .Comments}"
SelectionMode = "None"
SeparatorVisibility = "None"
RowHeight = "220"
VerticalOptions = "StartAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "40"/>
<RowDefinition Height = "40"/>
<RowDefinition Height = "40"/>
<RowDefinition Height = "40"/>
<RowDefinition Height = "5"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "10"/>
<ColumnDefinition Width = "90"/>
<ColumnDefinition Width = "80"/>
<ColumnDefinition Width = "400"/>
<ColumnDefinition Width = "80"/>
</Grid.ColumnDefinitions>
<Label Grid.Row = "0" Grid.Column = "1" WidthRequest = "80" Text = "Rel (in):" VerticalOptions = "Start" />
<Entry Grid.Row = "0" Grid.Column = "2" WidthRequest = "80" Text = "{Binding RelDepth}" VerticalOptions = "Start" />
<Label Grid.Row = "1" Grid.Column = "1" WidthRequest = "80" Text = "Abs (ft):" />
<Label Grid.Row = "1" Grid.Column = "2" WidthRequest = "80" Text = "{Binding AbsDepth}" />
<Editor Grid.Row = "0" Grid.Column = "3" Grid.RowSpan = "4"
WidthRequest = "400"
HeightRequest = "120"
Text = "{Binding Text}"
Placeholder = "Comment(s)..."
BackgroundColor = "#EFEFEF"
Style = "{StaticResource BigBlackTextEntry}"
HorizontalOptions = "StartAndExpand"
VerticalOptions = "Start"/>
<Button Grid.Row = "3" Grid.Column = "1" WidthRequest = "90" HeightRequest = "50" Text = "Remove" />
<BoxView Grid.Row = "4" Grid.Column = "1" Grid.ColumnSpan = "4" HeightRequest = "1" BackgroundColor = "Cyan" />
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
В коде я установил контекст привязки следующим образом:
/// in the class instance data...
private CommentBinding ViewModel { get; set; }
/// elsewhere - in the constructor
ViewModel = new CommentBinding() { Comments = theModels };
BindingContext = ViewModel;
/// when an item is added
private void NewCommentClicked(object sender, EventArgs e)
{
try
{
DepthModel newComment = new DepthModel() { RelDepth=0 };
newComment.RecalcAbsDepth(_startingAbsDepthInches);
ViewModel.Comments.Add(newComment);
ViewModel.NotifyChange();
}
catch (Exception exception)
{
// log error... etc
}
}
На прилагаемом снимке экрана показаны 3 элемента списка. Первые два доступны для редактирования, и все работает. 3-й пункт не позволяет вводить какие-либо данные (как если бы элементы управления были отключены - но мы этого не делаем) и кнопка "Удалить" не реагирует.
Обратите внимание, что StackView, который обертывает ListView, должен был быть добавлен, чтобы ListView правильно позиционировался (это еще одна загадка) - и 1200 HeightRequest - это эксперимент, чтобы увидеть, влияет ли это на странное поведение - меня это не беспокоит. об этом прямо сейчас.
Все идеи, конечно, приветствуются.
На основе вашего кода я создал новую демо-версию и опробовал ее на своей стороне. Но я обнаружил, что ListView не может прокручиваться.
И я обнаружил известную проблему в ListView и CollectionView, которые не прокручиваются в вертикальном StackLayout, поэтому мы можем использовать Grid
вместо StackLayout
снаружи ListView
.
Вы можете обратиться к следующему коду:
<ContentPage.Content>
<Grid VerticalOptions = "StartAndExpand" >
<Grid.RowDefinitions>
<RowDefinition Height = "60" />
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<VerticalStackLayout>
<Button WidthRequest = "200" HeightRequest = "50" Text = "Add New" HorizontalOptions = "Center" Command = "{Binding AddNewCommand}"/>
<BoxView HeightRequest = "10" />
</VerticalStackLayout>
<!--<StackLayout Orientation = "Vertical" VerticalOptions = "StartAndExpand" HeightRequest = "1200">-->
<ListView x:Name = "CommentsList" Grid.Row = "1"
ItemsSource = "{Binding Comments}"
SelectionMode = "None"
SeparatorVisibility = "None"
RowHeight = "220"
VerticalOptions = "StartAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "40"/>
<RowDefinition Height = "40"/>
<RowDefinition Height = "40"/>
<RowDefinition Height = "40"/>
<RowDefinition Height = "5"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "10"/>
<ColumnDefinition Width = "90"/>
<ColumnDefinition Width = "80"/>
<ColumnDefinition Width = "400"/>
<ColumnDefinition Width = "80"/>
</Grid.ColumnDefinitions>
<Label Grid.Row = "0" Grid.Column = "1" WidthRequest = "80" Text = "Rel (in):" VerticalOptions = "Start" />
<Entry Grid.Row = "0" Grid.Column = "2" WidthRequest = "80" Text = "{Binding RelDepth}" VerticalOptions = "Start" />
<Label Grid.Row = "1" Grid.Column = "1" WidthRequest = "80" Text = "Abs (ft):" />
<Label Grid.Row = "1" Grid.Column = "2" WidthRequest = "80" Text = "{Binding AbsDepth}" />
<Editor Grid.Row = "0" Grid.Column = "3" Grid.RowSpan = "4"
WidthRequest = "400"
HeightRequest = "120"
Text = "{Binding Text}"
Placeholder = "Comment(s)..."
BackgroundColor = "#EFEFEF"
HorizontalOptions = "StartAndExpand"
VerticalOptions = "Start"/>
<Button Grid.Row = "3" Grid.Column = "1" WidthRequest = "90" HeightRequest = "50" Text = "Remove" Command = "{Binding BindingContext.RemoveCommand,Source = {x:Reference CommentsList}}" CommandParameter = "{Binding .}" />
<BoxView Grid.Row = "4" Grid.Column = "1" Grid.ColumnSpan = "4" HeightRequest = "1" BackgroundColor = "Cyan" />
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!--</StackLayout>-->
</Grid>
</ContentPage.Content>
Кроме того, поскольку вы используете MVVM, мы обычно больше не рекомендуем изменять данные в модели представления в C#, а использовать команду в ViewModel.
Итак, вы можете добавить команду AddNewCommand
для кнопки Add New
и команду RemoveCommand
для кнопки Remove
в свою модель представления.
public ICommand AddNewCommand { get; set; }
public ICommand RemoveCommand { get; set; }
Вы можете обратиться к следующему коду:
public class CommentViewModel
{
public ObservableCollection<DepthModel> Comments { get; set; }
public ICommand AddNewCommand { get; set; }
public ICommand RemoveCommand { get; set; }
public CommentViewModel() {
Comments = new ObservableCollection<DepthModel>();
Comments.Add(new DepthModel { AbsDepth = "01", RelDepth = 01, Text = "Hi 1"});
Comments.Add(new DepthModel { AbsDepth = "02", RelDepth = 022, Text = "Hi 2"});
Comments.Add(new DepthModel { AbsDepth = "03", RelDepth = 033, Text = "Hi 3"});
Comments.Add(new DepthModel { AbsDepth = "04", RelDepth = 044, Text = "Hi 4"});
Comments.Add(new DepthModel { AbsDepth = "05", RelDepth = 055, Text = "Hi 5"});
RemoveCommand = new Command((s)=> RemoveItem(s as DepthModel));
AddNewCommand = new Command(AddItem);
}
private void AddItem()
{
DepthModel newComment = new DepthModel() { RelDepth = 6 };
//newComment.RecalcAbsDepth(_startingAbsDepthInches);
Comments.Add(newComment);
}
private void RemoveItem(DepthModel depthModel)
{
if (depthModel == null) return;
System.Diagnostics.Debug.WriteLine("remove current item.");
Comments.Remove(depthModel);
}
}
И код MainPage.xaml.cs
:
public partial class MainPage : ContentPage
{
public CommentViewModel viewModel { get; set; }
public MainPage()
{
InitializeComponent();
viewModel = new CommentViewModel();
this.BindingContext = viewModel;
}
}
public class DepthModel
{
public int RelDepth { get; set; }
public string AbsDepth { get; set; }
public string Text { get; set; }
}
Примечание:
Основываясь на приведенном выше коде, я не смог воспроизвести упомянутую вами проблему на платформах Android и Windows.
@Джесси: Это помогло. Но мне интересно, почему это НЕ работало в предыдущей реализации? Кажется немного странным, что элементы в представлении списка работают ДО тех пор, пока в списке не будет более двух элементов. Это похоже на ошибку, но не связанную с прокруткой (проблема была не в этом).
Я пытался начать без элементов в списке и добавлять их один за другим, но проблем, о которых вы говорили, не возникло. :)
But I'm curious as to why it did NOT work in the previous implementation?
Я также попробовал реализацию, которую вы опубликовали в этой задаче, но все еще не могу воспроизвести проблему. Конечно, если пользовательский интерфейс длиннее одного экрана, ListView невозможно прокручивать.
Джесси: Кажется, это очень полезно. Я попробую и отчитаюсь. Команды RE в модели представления: Да. Это устаревший код, поэтому мне еще предстоит перейти на этот подход. Это следующее в списке....