简体   繁体   中英

How to perform a text search on other pages (labels) in Xamarin.Forms

I'm new in a Xamarin development. I hope that you can resolve my problem in a simple mode.

i've a crossplatform app developed with xamarin. In one page of the app i want to give the possibility to search a word and redirecting the user to the page that he want. i will describe you the situation.

i have a page with a list view (listview.xaml). every item of list view is used like a buttons to go in other pages (page1.xaml; page2.xaml; page3.xaml; etc...). in this pages there are some text (in label). so i want that if i search the word "example" in the listpage.xaml i receive as results all the pages where the word "example" exist and use the results to navigate to the correct page where the word "example" is.

Please, if you can, give me a simple solution. Thanks.

this is my listview.xaml

<ContentPage.Content>
        <StackLayout Orientation="Vertical">
            <StackLayout Margin="10,10,0,0">
                <StackLayout BackgroundColor="#2B2B2B" Padding="0" Margin="-10,-10,0,0">
                <SearchBar TextColor="White" Placeholder="Cerca la parola chiave..." Margin="-5,0,0,0" />
               </StackLayout>
                <ListView ItemTapped="argomentilist_ItemTapped" x:Name="argomentilist" RefreshControlColor="#1F9F73">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Orientation="Vertical" BackgroundColor="{Binding BackgroundColor}">
                                <Label Text="{Binding Capitolo}" Font="18" TextColor="Black"></Label>
                                <Label Text="{Binding Descrizione}" Font="14" TextColor="Gray"></Label>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
        </StackLayout>
    </ContentPage.Content>

i will try to help you:)

<?xml version="1.0" encoding="utf-8" ?>  
 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
         xmlns:local="clr-namespace:crossplatformapp"  
         x:Class="crossplatformapp.MainPage">  

<StackLayout>  
    <SearchBar TextChanged="SearchBar_TextChanged"></SearchBar>  
    <ListView x:Name="list">  
        <ListView.ItemTemplate>  
            <DataTemplate>  
                <TextCell Text="{Binding Name}" Detail="{Binding Num}">   

                </TextCell>  
            </DataTemplate>  
        </ListView.ItemTemplate>  
    </ListView>  

</StackLayout>  

and

namespace crossplatformapp  
{  
public partial class MainPage : ContentPage  
{  
    public List<Contacts> tempdata;  
    public MainPage()  
    {  
        InitializeComponent();  
        data();  
        list.ItemsSource = tempdata;  

    }  

    public void data()  
    {  
        // all the temp data  
        tempdata = new List<Contacts> {  
            new Contacts(){ Name = "umair", Num = "2323423"},  
            new Contacts(){ Name = "saleh", Num = "23423"},  
            new Contacts(){ Name = "umair", Num = "233423423"},  
            new Contacts(){ Name = "sanat", Num = "2423"},  
            new Contacts(){ Name = "jawad", Num = "323423"},  
            new Contacts(){ Name = "shan", Num = "2323423"},  
            new Contacts(){ Name = "ahmed", Num = "2323423"},  
            new Contacts(){ Name = "abc", Num = "2323423"},  
            new Contacts(){ Name = "umair", Num = "2323423"},  
            new Contacts(){ Name = "etc", Num = "2323423"},  
        };  
    }  

    private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)  
    {  
        //thats all you need to make a search  

        if (string.IsNullOrEmpty(e.NewTextValue))  
        {  
            list.ItemsSource = tempdata;  
        }  

        else  
        {  
            list.ItemsSource = tempdata.Where(x => 
 x.Name.StartsWith(e.NewTextValue));  
        }  
    }  
}  

Disclaimer:

This is just a way to achieve the requirements set in the Original Post (OP), and by no means imply that the code that it involves is the best possible, or intended to be Production-like code. IT IS JUST A WAY TO ACHIEVE WHAT THE OP REQUIRES.


Let's create a Page ( ListView.xaml ) with a ListView that lists a couple of items that refer to chapters of a book. Each item, when clicked launches a page with the contents of that chapter.

Also, at the top of that ListView Page there is a SearchBar : when you make a search, the App will check if any of the pages referred by items contain the searched text.

ListView.xaml:

<StackLayout>

    <SearchBar SearchButtonPressed="SearchBar_SearchButtonPressed" TextChanged="SearchBar_TextChanged"/>

    <ListView x:Name="listView"
              ItemTapped="listView_ItemTapped">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextCell Text="{Binding Chapter}"
                          Detail="{Binding Description}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</StackLayout>

While on the code behind we set the ItemsSource of the ListView , and define the EventHandlers for the search (Bonus: Note the EventHandler SearchBar_TextChanged to return to the orignial list when you clear the search bar:):

ListView.xaml.cs:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Xamarin.Forms;

namespace SearchContent
{
    public partial class ListView : ContentPage
    {

        ObservableCollection<Content> contents { get; set; }
        public ListView()
        {
            InitializeComponent();
        }

        protected override void OnAppearing()
        {

            base.OnAppearing();

            contents = new ObservableCollection<Content>()
            {
                new Content("Chapter 1", "Description of Chapter 1", new Page1()),
                new Content("Chapter 2", "Description of Chapter 2", new Page2()),
            };

            listView.ItemsSource = contents;

        }


        private void listView_ItemTapped(object sender, ItemTappedEventArgs e)
        {
            Navigation.PushAsync(((Content)e.Item).ChapterPage);
        }

        private void SearchBar_SearchButtonPressed(object sender, EventArgs e)
        {
            String textToSearch = ((SearchBar)sender).Text;

            var contentsFiltered = contents.Where(item => ((Interface1)item.ChapterPage).PageText.Contains(textToSearch));

            ObservableCollection<Content> newContents = new ObservableCollection<Content>(contentsFiltered);

            listView.ItemsSource = null;
            listView.ItemsSource = newContents;

        }

        private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
        {
            if(String.IsNullOrEmpty(e.NewTextValue))
            {
                listView.ItemsSource = null;
                listView.ItemsSource = contents;
            }
        }
    }


    public class Content
    {
        public String Chapter { get; set; }

        public String Description { get; set; }

        public Page ChapterPage { get; set; }

        public Content(String chapter, String description, Page chapterPage)
        {

            Chapter = chapter; 
            Description = description;
            ChapterPage = chapterPage;

        }

    }

}

Now you just need the Pages with the text: Page1 and Page2 .

First of all i define an Interface Interface1 that those pages will implement. The use of this interface is to define a single property: PageText . By implementing this interface in Page1 and Page2 i was able to cast each item in the ListView to Interface1 in the EventHandler SearchBar_SearchButtonPressed in ListView.xaml.cs .

Interface1.cs :

interface Interface1
{
    string PageText { get; set; }
}

And now the Pages:

Page1.xaml

<StackLayout>
    <Label Text="{Binding PageText}"
           VerticalOptions="CenterAndExpand" 
           HorizontalOptions="CenterAndExpand" />
</StackLayout>

Page1.xaml.cs :

public partial class Page1 : ContentPage,Interface1
{

    public String PageText { get; set; }

    public Page1()
    {

        PageText =
           "This is the display of the inquiry of Herodotus of Halicarnassus, " +
           "so that things done by man not be forgotten in time, and that great " +
           "and marvelous deeds, some displayed by the Hellenes, some by the " +
           "barbarians, not lose their glory, including among others what was the " +
           "cause of their waging war on each other. ";

        InitializeComponent();

        BindingContext = this;
    }

}

And similarly,

Page2.xaml

<StackLayout>
    <Label Text="{Binding PageText}"
           VerticalOptions="CenterAndExpand" 
           HorizontalOptions="CenterAndExpand" />
</StackLayout>

Page2.xaml.cs

public partial class Page2 : ContentPage, Interface1
{
    public String PageText { get; set; }

    public Page2()
    {
        PageText =
        "The Persian learned men say that the Phoenicians were the cause " +
        "of the dispute. These (they say) came to our seas from the sea " +
        "which is called Red,1 and having settled in the country which " +
        "they still occupy, at once began to make long voyages. Among other " +
        "places to which they carried Egyptian and Assyrian merchandise, " +
        "they came to Argos";

        InitializeComponent();

        BindingContext = this;
    }
}

But what if you HAD to read the labels themselves? Well, that is not a good practice (since that would meant that you keep those objects referenced and occupying resources) and i can not imagine a case where that MUST be.

But If I had to do that i think a way would be to define the labels either as Public or as Public static in Page2 . In the first case you have to keep a reference to Page2 myPage2 = new Page2() to be able to read its Public Label ( myPage2.myPublicLabel ). In the second case it is only the Label that remains referenced, and can be then retrieved as Page2.mystaticLabel . You would naturally first have to check if the Label is already assigned, etc...


So far, the problem as described in the OP should be solved, nonetheless it might be worth giving a try to a different approach:

Instead of creating Page1 , Page2 , etc you might want to extend your objects (the ones that feed the ListView , and called Content in my sample above) to include a String property ChapterText that contains the text meant to be displayed in the other Pages. If done so, you can create a generic Page whose constructor takes one of those objects as parameter and uses ChapterText as the text for the Page . Doing that you can then perform the search from the SearchBar without casting to the Interface1 , but directly in the ChapterText property of the items...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM