February 2017

Volume 32 Number 2

[Modern Apps]

Twitter-Searching Utility

By Frank La

Frank La VigneIn my column last month, I explored the great Universal Windows Platform (UWP) Community Toolkit, an open source toolkit built by the community for the community. However, I barely scratched the surface of what it can do. The UWP Community Toolkit makes building highly polished, cloud-powered UWP apps much easier and faster. In this month’s column, I’ll discuss how to build a Twitter search app using the Twitter services and the blade control to demonstrate how easy it is to work with.

Currently, I manage several YouTube channels that source content from tweets marked with certain hashtags. For example, #DCTech Minute focuses on the happenings in the DC Area startup and technology scene. I find content to highlight based on tweets that use the DCTech hashtag. For #Node.js Minute, I do the same with tweets marked with #Node.js. Currently, I do a lot of manual cutting and pasting between Twitter and OneNote. It would be great to have a UWP app that can search Twitter for all the key phrases I need all in one window and make it easier to pull the content from the tweets.

Setting up the Project

Create a new blank UWP project in Visual Studio by choosing New Project from the File menu. Expand the Installed Templates | Windows | Blank App (Universal Windows). Name the project TagSearcherUWP and then click OK. Immediately afterward, a dialog box will appear asking you which version of Windows the app should target. At a minimum, you’ll need to choose Windows 10 Anniversary Edition (10.0; Build 14393). This is the most recent version. Therefore, both the Target Version and the Minimum Version will both target the same version, as shown in Figure 1. If you don’t see this particular version in either dropdown list, then make sure you have the appropriate software installed on your system. Failure to select the correct version will yield a runtime error once the Microsoft.Toolkit.Uwp.UI.Controls NuGet package is added to the project. 

Targeting the Correct Version of Windows
Figure 1 Targeting the Correct Version of Windows

Once the solution loads, browse to Solution Explorer, then right-click on References and choose Manage NuGet Packages from the context menu to show the NuGet Package Manager. In the search box, type “Microsoft.Toolkit.Uwp” to bring up all the NuGet packages associated with the UWP Community Toolkit. This project will use the Microsoft.Toolkit.Uwp.Services and Microsoft.Toolkit.Uwp.UI.Con­trols packages. Install them both to add them to the project. If prompted with a Review Changes dialog, review the changes and then click OK to accept. You’ll also see a License Acceptance dialog for each package. Click “I Accept” to accept the license terms. Clicking “I Decline” will cancel the install.

Setting Up Twitter

Now that the project is set up with the appropriate NuGet packages, it’ time to connect the app to the Twitter service. Go to apps.twitter.com and sign in with your Twitter account. If you don’t have a Twitter account, you should make one now. If you haven’t created a Twitter App, you’ll need to click on Create New App to register a new app.

You’ll need to fill out details about the app, such as the Name, Description, Web site and Callback URL. You can fill in the fields as you wish. For the name, I chose MSDNTagSearchUWPApp. End users will see the Description text when they log in, so it’s best to make it short and descriptive. See Figure 2 for guidance. For both the Web site and Callback fields, I put in my Web site URL. In the case of UWP apps, the callback URL doesn’t have to be a working URL. Make note of the URL as you’ll need it later when logging into the service. Check the checkbox next to the Developer Agreement and click the Create your Twitter application button.

Creating a New Twitter App
Figure 2 Creating a New Twitter App

Once the app is created, click on the Keys and Access Tokens tab and note the Consumer Key (API Key) and Consumer Secret (API Secret) fields, as shown in Figure 3. You’ll use them shortly.

The Consumer Key and Access Token Tab
Figure 3 The Consumer Key and Access Token Tab

Creating the UI

Open the MainPage.xaml file and add the XAML in Figure 4. Note that there’s an added namespace for the controls in the UWP Community Toolkit. This is where the BladeView control resides:

Figure 4 XAML Code to Create the Interface

<Page
  x:Class="TagSearcherUWP.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:TagSearcherUWP"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d">
  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
      <RowDefinition Height="56*"/>
      <RowDefinition Height="35*"/>
      <RowDefinition Height="549*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
      <TextBlock FontSize="24" Margin="5">Twitter Tag Searcher</TextBlock>
      <Button Name="btnLogin" Click="btnLogin_Click" >Log In</Button>
    </StackPanel>
    <StackPanel Name="splSearch" Grid.Row="1"  Orientation="Horizontal"
      VerticalAlignment="Center" Visibility="Collapsed">
      <TextBox Name="txtSearch" Margin="5,0,5,0"  MinWidth="140" Width="156" />
      <Button Name="btnSearch" Click="btnSearch_Click">Search</Button>
    </StackPanel>
    <controls:BladeView Name="bladeView" Grid.Row="2" Margin="12"
      HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
      <controls:BladeItem x:Name="DummyBlade" IsOpen="False" />
    </controls:BladeView>
  </Grid>
</Page

Introducing the BladeView Control

The BladeView control will look familiar to users of the Azure Portal Web site (portal.azure.com). If you’re unfamiliar with it, the BladeView control provides a container to host “blades” or tiles. The XAML in Figure 4 includes a “DummyBlade” to keep the XAML designer view from crashing. It’ll throw an exception if it encounters a BladeView without any BladeItems. Because the IsOpen property is set to False, users will never see the BladeItem.

Logging into Twitter

Next, connect the app to the Twitter API by adding the following event handler for the btnLogin_Click event:

private async void btnLogin_Click(object sender, RoutedEventArgs e)
  {
    string apiKey = "pkfAUvqfMAGr53D4huKOzDYDP";
    string apiSecret =
      "bgJCH9ESj1wraCoHBI5OqEqhkac1AOZxujqvnCWKNRJgBMhyPG";
    string callbackUrl = "http://www.franksworld.com";
    TwitterService.Instance.Initialize(apiKey, apiSecret, callbackUrl);
    if (await TwitterService.Instance.LoginAsync())
    {
      splSearch.Visibility = Visibility.Visible;
    }
  }

The code uses the API Key, API Secret, and Callback URL fields and uses them in the parameters of the Initialize method of the TwitterService.Instance. TwitterService.Instance is a singleton that will maintain state throughout the entire app. Calling the Login­Async method initiates the call to the Twitter API. If the login is successful, the method returns true. In that case, you should make the StackPanel with the Search Controls visible.

Displaying Search Results

With the Twitter API calls set up, it’s time to create a place for the search results to be displayed. To do this, you’ll create a user control. The user control will contain code to perform the Twitter API search, as well as host the necessary controls to display the search results.

To get started, right-click on the project and choose Add | New Item in the context menu. In the following dialog box, look for user control. Name the user control SearchResults and click Add, as shown in Figure 5.

Adding a New User Control to the Project
Figure 5 Adding a New User Control to the Project

Modify the SearchResults.xaml file to add the XAML found in Figure 6.

Figure 6 XAML for the SearchResults User Control

<Grid>
  <ListView Name="lvSearchResults" Width="350" >
  <ListView.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="0,4,4,0">
        <Image Source="{Binding User.ProfileImageUrl}" Width="64"
          Margin="8"  ></Image>
          <StackPanel Width="240">
            <TextBlock Text="{Binding Text}"
              TextWrapping="WrapWholeWords"></TextBlock>
            <TextBlock Text="{Binding CreationDate}"
              FontStyle="Italic" ></TextBlock>
            <TextBlock Text="{Binding User.ScreenName}"
              Foreground="Blue"></TextBlock>
            <TextBlock Text="{Binding User.Name}"></TextBlock>
          </StackPanel>
        </StackPanel>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</Grid>

The XAML contains a ListView and the necessary DataTemplate to display the Twitter search results. Open the SearchResults.xaml.cs file and add the following property to the Search Results class:

public string SearchTerm { get; private set; }

Then, modify the constructor to add a string parameter for the search term:

public SearchResults(string searchTerm)
{
  this.InitializeComponent();
  this.SearchTerm = searchTerm;
  Search();
}

Now, add the following method:

private async void Search()
  {
    lvSearchResults.ItemsSource = await  
    TwitterService.Instance.SearchAsync(this.SearchTerm, 50);
  }

The Search method calls the SearchAsync method with two parameters: the search term and the limit of results to return. All the underlying REST API plumbing work is done by the UWP Community Toolkit.  

Now that the SearchResults user control is ready, it’s time to add code to the MainPage.xaml.cs file to complete the app. Add the following event handler for the btnSearch Button control:

private void btnSearch_Click(object sender, RoutedEventArgs e)
  {
    BladeItem bi = new BladeItem();
    bi.Title = txtSearch.Text;
    bi.Content = new SearchResults(txtSearch.Text);
    bladeView.Items.Add(bi);
  }

The BladeView control can contain any number of BladeItems. The previous code snippet creates a BladeItem control and sets the Title of the BladeItem to the text from the search textbox. Next, it sets the contents of the BladeItem control to a new instance of the SearchResults user control, passing the search term off to the constructor. Finally, it adds the BladeItem to the BladeView.

Run the solution now. Click the Log In button. When prompted, enter your Twitter credentials and grant the app the permissions it’s asking for. The window will close and the search panel will now be visible. After entering a few search terms, your screen should look something like Figure 7.

The Tag Search App in Action
Figure 7 The Tag Search App in Action

Adding the Copy Function

Now that you have all the tweets you’re interested in neatly organized by blade, you need a way to get the data into a text format. Ideally, you’d like to be able to right-click (or tap, if on a touchscreen device) and copy the contents of the tweet to the clipboard. Adding this feature requires some modification to the XAML and code for the SearchResults user control.

Inside the SearchResults.xaml file, you want to add a flyout menu to the ListView control. Inside the ListView tag add the following XAML to create a MenuFlyout as a resource within the ListView control:

<ListView.Resources>
  <MenuFlyout x:Name="mfCopyMenu">
    <MenuFlyout.Items>
      <MenuFlyoutItem Name="mfiCopy" Text="Copy" Click="mfiCopy_Click"/>
    </MenuFlyout.Items>
  </MenuFlyout>
</ListView.Resources>

While still in the SearchResults.xaml file, add the following event handler to the ListView control to detect when the ListView is right-clicked or tapped:

RightTapped="lvSearchResults_RightTapped"

Now add the following event handler code in the Search­Results.xaml.cs file:

private void lvSearchResults_RightTapped(object sender, 
  RightTappedRoutedEventArgs e)
{
  var tweet = ((FrameworkElement)e.OriginalSource).DataContext;
  mfiCopy.Tag = tweet;
  mfCopyMenu.ShowAt(lvSearchResults, 
    e.GetPosition(lvSearchResults));
}

The purpose of this code is to capture the tweet object from the DataContext and store it into the MenuFlyoutItem Tag property. The Tag property is inherited from FrameworkElement and is meant to store custom information about an object. Once the selected tweet object is stored in the Tag property of the MenuFlyoutItem, it’s time to display the flyout menu. Users expect a context menu to appear where they clicked or tapped on the screen. That’s why the code sends event position information to the ShowAt method.

Now it’s time to add the event handler for the MenuFlyoutItem control and code to copy the contents of the tweet to the clipboard. Add the following event handler to the SearchResults.xaml.cs file:

private void mfiCopy_Click(object sender, RoutedEventArgs e)
{
  var menuFlyoutItemSender = (MenuFlyoutItem)sender;
  var tweet = menuFlyoutItemSender.Tag as Tweet;
  DataPackage dataPackage = new DataPackage();
  dataPackage.RequestedOperation = DataPackageOperation.Copy;
  dataPackage.SetText($"@{tweet.User.ScreenName} {tweet.Text} ");
  Clipboard.SetContent(dataPackage);
}

The first two lines of code retrieve the tweet data from the Tag property of the MenuFlyoutItem. Once that’s obtained, it’s time to send data to the clipboard. In UWP apps, this is done by using the DataPackage class. A full exploration of the DataPackage class is beyond the scope of this column; however, if you’re interested in learning more, I recommend reading the “Copy and Paste” documentation page at bit.ly/2h54IK0. The “DataPackage Class” documentation page is at bit.ly/2hpo2Fc.

The clipboard can handle robust formatting of text and images. However, for this column, I’m interested only in the text contents of the tweet and the Twitter handle of the person who made it. The UWP Community Toolkit stores that as ScreenName inside the User object. Finally, I set the contents of the Clipboard to the DataPackage object.

Run the solution now, log in, and enter a search term. Find a tweet you wish to copy, right-click or tap to see the context menu, as shownin Figure 8. Click Copy.

Testing the Copy Context Menu Function on a Sample Tweet
Figure 8 Testing the Copy Context Menu Function on a Sample Tweet

Now, run Notepad, or your favorite text editor, and chose Edit | Paste or use Ctrl+V. You should see this text from the tweet: @AndyLeonard Reading “Going Rogue” by my brother and friend, Frank La Vigne. :{&gt; https://t.co/JnuAzqO6m5.

Wrapping Up

As you can see, the UWP Community Toolkit facilitates rapid development of cloud-connected UWP apps. It only took one line of code to log into Twitter. Searching Twitter was equally as brief. Most of the code had more to do with the presentation of the data and how users interact with it. The UWP Community Toolkit provides rich UI controls, as well as straightforward ways to access popular cloud APIs such as Twitter. Low-level REST API and authentication mechanisms are abstracted away into a clean IntelliSense-enabled API. This enables developers to focus on how users interact with the data, rather than obtaining the data. The UWP Community Toolkit can make any UWP app better and easier to connect to social media and other cloud services.


Frank La Vigne is an independent consultant, where he helps customers leverage technology in order to create a better community. He blogs regularly at FranksWorld.com and has a YouTube channel called Frank’s World TV (FranksWorld.TV).

Thanks to the following technical experts for reviewing this article: David Catuhe


Discuss this article in the MSDN Magazine forum