У меня есть пользовательская ячейка, отображаемая в виде списка.Он должен не работать, но я обеспокоен тем, что он работает, и я не понимаю, почему.
Позвольте мне изложить вам кое-что, потому что это немного сложно.
По сути, я отображаю список контактов с полем поиска вверху.У меня есть несколько других вещей, которые могут быть показаны за рамками этого вопроса, но для ясности вы увидите их в коде, особенно в xaml и в селекторе шаблонов данных.
Я использую разныетипы пользовательских ячеек для отображения каждой части моего списка контактов (есть ячейка заголовка, ячейка поиска и некоторые другие).
Здесь ContactsPage
содержит представление списка и объявление таблицы данных.
<ContentPage>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="HeaderTemplate">
<ViewCell>
<StackLayout>
<local:HeaderView/>
</StackLayout>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="SearchTemplate">
<local:SearchCell/> //<=== Important
</DataTemplate>
<DataTemplate x:Key="CategoryTemplate">
<ViewCell
x:Name="CategoryCell">
<Label
Text="CategoryCell" ></Label>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="SelectionTemplate">
<ViewCell
x:Name="SelectionCell">
<Label
Text="Selection Cell" ></Label>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="ContactTemplate">
<ViewCell
x:Name="ContactCell">
<Label
Text="{Binding FirstName}" ></Label>
</ViewCell>
</DataTemplate>
<local:ContactDataTemplateSelector x:Key="TemplateSelector"
HeaderTemplate="{StaticResource HeaderTemplate}"
SearchTemplate="{StaticResource SearchTemplate}"
CategoryTemplate="{StaticResource CategoryTemplate}"
SelectionTemplate="{StaticResource SelectionTemplate}"
ContactTemplate="{StaticResource ContactTemplate}"/>
</ResourceDictionary>
</ContentPage.Resources>
Видите ли, у меня есть различные шаблоны данных, каждый для своего собственного использования.Заголовок работает, остальное находится в процессе выполнения, единственное, что меня волнует - это реализация Search .От ячейки до модели представления и шаблона данных.
Теперь это были только ресурсы, вот фактический пользовательский интерфейс страницы (только соответствующий код)
<ContentPage.Content>
... Content of the page, including the actual listview
<ListView
x:Name="ContactsListView"
HasUnevenRows="True""
ItemTemplate="{StaticResource TemplateSelector}"
ItemsSource="{Binding ListSource}">
</ListView>
</ContentPage.Content>
Позвольте мне взять васчерез путешествие логики позади этого, в модели представления этого взгляда.Код позади самого представления ничего не делает, и вот ViewModel этого списка контактов.
public class ContactsViewModel : BaseViewModel, IContactsViewModel
{
readonly IContactsService _service;
List<object> _listSource;
public List<object> ListSource
{
get => _listSource;
private set
{
_listSource = value;
OnPropertyChanged();
}
}
public string CurrentText => "HelloX"; //<=== Important
readonly ISearchViewModel _searchViewModel;
readonly ICategoryFilterViewModel _categoryFilterViewModel;
readonly ISelectionViewModel _selectionViewModel;
public ContactsViewModel()
{
_service = new();
HeaderViewModel = new HeaderViewModel();
_searchViewModel = new();
_categoryFilterViewModel = new();
_selectionViewModel = new();
ListSource = GenerateDefaultList();
}
public async Task LoadContacts() //Called when UI appears.
{
await _service.LoadContacts();
var list = GenerateDefaultList();
list.AddRange(_service.Contacts);
ListSource = list;
}
List<object> GenerateDefaultList()
{
return new List<object>()
{
HeaderViewModel,
_searchViewModel, //<===== important
_categoryFilterViewModel,
_selectionViewModel
};
}
}
Я включаю большую часть кода для ясности;Важная часть, которую я хочу подчеркнуть, состоит в том, что ListSource
уже имеет несколько моделей представления внутри него.Я использую этот источник для заполнения моего списка, и тип объекта определяет, какой тип шаблона данных я буду использовать.Это делается в селекторе DataTemplate, который находится здесь:
public class ContactDataTemplateSelector : DataTemplateSelector
{
public DataTemplate ContactTemplate { get; set; }
public DataTemplate HeaderTemplate { get; set; }
public DataTemplate SearchTemplate { get; set; }
public DataTemplate CategoryTemplate { get; set; }
public DataTemplate SelectionTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
switch (item)
{
case HeaderViewModel _:
return HeaderTemplate;
case SearchViewModel _:
return SearchTemplate; //<==== important
case CategoryFilterViewModel _:
return CategoryTemplate;
case SelectionViewModel _:
return SelectionTemplate;
default:
return ContactTemplate;
}
}
}
Итак, у меня есть экземпляр SearchViewModel
(единственный важный по моему вопросу), но нигде не сказано, чтоViewCell шаблона данных поиска фактически использует SearchViewModel.Я просто использую его как условие для моего оператора if
.
Вот ячейка поиска, которая используется в шаблоне данных (который сам выбирается с помощью селектора шаблона данных)
<ViewCell x:Class="MYNAMESPACE.SearchCell">
<AbsoluteLayout>
<Frame>
<StackLayout>
<Entry
Placeholder="{Binding PlaceHolderText}"/>
<Button
Text="{Binding CurrentText}"
Command="{Binding SearchCommand}"/>
</StackLayout>
</Frame>
</AbsoluteLayout>
</ViewCell>
Я удалил столько, сколько мог, не рискуя затенить контекст.Я знаю, что это стена кода, но я считаю, что это будет полезно, если вы решите исследовать.
Насколько я понимаю, я никогда не предоставляю привязывающий контекст для своего пользовательского ViewCell (поисковой ячейки).У меня есть привязки внутри, в частности, мой рабочий пример - CurrentText
.У меня есть это как текст в моем SearchViewModel
public class SearchViewModel : ISearchViewModel
{
public string CurrentText => "<TODO SEARCH>"; //<=== Important
//NotifyPropertyChanged Implementation
}
У меня есть другой CurrentText
в ContactsViewModel
, но текст, который отображается во время выполнения, тот из SearchViewModel
.Я вижу "", а не "HelloX".Это то, что я хочу.Я просто не понимаю, как / почему в ячейке используется моя viewmodel.
Я использую только viewmodel, чтобы выбрать, какой шаблон данных отображать, нигде эта viewmodel не задается в качестве связующего контекста этого шаблона данных, ни viewcell.,Или я?Откуда берется контекст привязки?