代码之家  ›  专栏  ›  技术社区  ›  Gil Sand

Xamarin表单中数据模板视图单元格内的绑定上下文

  •  1
  • Gil Sand  · 技术社区  · 6 年前

    我在列表视图中显示了一个自定义单元格。应该的 但我担心的是,它的工作,我不明白为什么。

    我来给你安排一下,因为有点复杂。

    我使用不同类型的自定义单元格来显示联系人列表的每一部分(有一个标题单元格、一个搜索单元格等等)。

    在这里, ContactsPage 包含listview和datatemplate的声明。

    <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>
    

    你看,我有各种各样的数据模板,每个都有自己的用途。头正在工作,其余的正在进行中 只有 我关心的是 实施。从单元到viewmodel,再通过数据模板。

    现在这只是资源,这里是实际的页面UI(只有相关代码)

    <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中。视图本身的代码不起任何作用,下面是该联系人列表的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

    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 if 声明。

    这是在数据模板中使用的搜索单元格(它本身是通过数据模板选择器选择的)

    <ViewCell x:Class="MYNAMESPACE.SearchCell">
        <AbsoluteLayout>
            <Frame>
                <StackLayout>
                    <Entry
                        Placeholder="{Binding PlaceHolderText}"/>
                    <Button
                        Text="{Binding CurrentText}"
                        Command="{Binding SearchCommand}"/>
                </StackLayout>
            </Frame>
        </AbsoluteLayout>
    </ViewCell>
    

    我尽可能多地删除了内容,而不冒着掩盖上下文的风险。我知道这是一堵代码墙,但我相信如果您决定进行调查,它会很有用。

    CurrentText . 我把它作为文本放在书里 搜索视图模型

    public class SearchViewModel : ISearchViewModel
        {
            public string CurrentText => "<TODO SEARCH>";     //<=== Important
    
            //NotifyPropertyChanged Implementation
        }
    

    我还有一个 当前文本 在里面 ContactsViewModel 搜索视图模型 . 我看到的是“”而不是“HelloX”。这就是我想要的。我只是不明白单元格如何/为什么使用我的viewmodel。

    我只使用viewmodel来选择要显示的数据模板,而不将viewmodel设置为该数据模板的绑定上下文,也不使用viewcell。还是我?绑定上下文从何而来?

    1 回复  |  直到 6 年前
        1
  •  4
  •   Ben Reierson    6 年前

    如果没有另外指定,页面上每个元素的BindingContext都是基于其父元素的设置的。我相信您可能已经看到,当您为页面设置BindingContext时,它会向下流到该页面的所有元素,除非您显式重写它。