Thursday, December 29, 2011

Add Scrolling Event in a List - WP7

Many of you might have been in  a situation when you desperately wanted to know if a scroll bar is scrolling or not.

Currently there is no direct provision to attain this in WP7. I'll walk through the code which will help you to identify if a list is scrolling or not. Later at the end there ia a full working sample attached.

My sample is straight forward. I'll be changing the page title to "Scrolling" when we scroll the list and "NotScrolling" while it is stationary.

We have a list called theList.

1. Now attach a Loaded event to the page constructor:

public MainPage()
{
    InitializeComponent();
    Loaded += new RoutedEventHandler(MainPage_Loaded);
    theList.ItemsSource = GetListData(60);
}

2. Define a variable to identify if ScrollEvent has been hooked already:

bool alreadyHookedScrollEvents = false;

3. Define MainPage_Loaded handler. All major work will be done here:

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    if (alreadyHookedScrollEvents)
        return;

    alreadyHookedScrollEvents = true;

    //This is the key player which holds the magic for this trick
    //This ScrollViewer is the first templated child of your List
    ScrollViewer viewer = FindSimpleVisualChild<ScrollViewer>(theList);

    if (viewer != null)
    {
        // Visual States are always on the first child of the control template 
        FrameworkElement element = VisualTreeHelper.GetChild(viewer, 0) as FrameworkElement;
        if (element != null)
        {
            VisualStateGroup group = FindVisualState(element, "ScrollStates");
            if (group != null)
            {
                group.CurrentStateChanging += group_CurrentStateChanging;
            }
        }
    }
}

4. Use this helper function to identify the first visual child (ScrollViewer):

T FindSimpleVisualChild<T>(DependencyObject element) where T : class
{
    while (element != null)
    {
        if (element is T)
            return element as T;
        element = VisualTreeHelper.GetChild(element, 0);
    }
    return null;
}

5. Actual even handler which identify a changed state for scrollviewer:

void group_CurrentStateChanging(object sender, VisualStateChangedEventArgs e)
{
    //for demonstration change page's title
    PageTitle.Text = e.NewState.Name;
}

6. Helper function to filter out the required VisualState:


VisualStateGroup FindVisualState(FrameworkElement element, string name)
{
    if (element == null)
        return null;

    IList<VisualStateGroup> groups = (IList<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(element);
    foreach (VisualStateGroup group in groups)
        if (group.Name == name)
            return group;

    return null;
}

     
7. Another helper function to fill the data in list to demonstrate implementation:


ObservableCollection<int> GetListData(int count)
{
    sourceList = new ObservableCollection<int>();
    for (int i = 1; i <= count; i++)
    {
        sourceList.Add(i);
    }
    return sourceList;
}

     
Source Code

Thursday, September 29, 2011

Windows Phone 7 and Emulator Shortcut Keys

KeyDescription
F1Use F1 key on the keyboard instead of back button on the phone
F2Use the key F2 on the keyboard for the Windows key in the Windows Phone 7
PageupEnables the keyboard in the emulator when the focus is on the textbox
PageDownDisables the keyboard in the emulator
F3To open the Bing Search
F7To Activate the Physical Camera
F9Increase the Volume
F10Decrease the volume

Additional link from MSDN





Thursday, August 25, 2011

Passing Data between Pages in Windows Phone 7


Passing data among pages is something which needs to be given a little care in terms what approach you follow . Since each approach has its own benefits and side effects. I'll try to explain each of them one by one.

For illustration of this concept I've created a sample code which is attached at the end of the article. In this project I've various project each corresponds to one approach which I've described below. Each project has two pages. Touching on the coloured part of one page takes you to another page. First page will display a text string which is provided by the second page. You can simply go to second page add some text into TextBox and you can touch the coloured part to go back to first page which displays the string which you entered on first page.

So here are the approaches one by one:

1. Using Global Variable: This is the easiest and quickest procedure to pass your data among various pages.

Define a "Global Variable" in your App.xaml file as:
public string SecondPageText { get; set; }

After that on your Second page on ManipulationStarted event for the coloured Border use this code:
App.Current as App).SecondPageText = txtBox.Text; // add value to Global variable
NavigationService.GoBack(); // Navigate to first page

PhonePageOne page add this:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
     base.OnNavigatedTo(e);
     txtBlock.Text = (App.Current as App).SecondPageText;
}

2. Using Query String: This procedure is good when we just need to share string based data between two pages.

Add this code in your PhonePageTwo:
private void Border_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
         string uri = "/PhonePageOne.xaml?Text=";
         uri += txtBox.Text;
         NavigationService.Navigate(new Uri(uri, UriKind.Relative));
}

Use this code in your PhonePageTwo:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
         IDictionary<string, string> parameters = this.NavigationContext.QueryString;
         if (parameters.ContainsKey("Text"))
         {
             txtBlock.Text = parameters["Text"];
         }
}

3. Using PhoneApplicationSerivce States: Every application has a PhoneApplicationService defined Microsoft.Phone.Shell. Each application has one PhoneApplicationService defined in its App.xaml file. We can use this service's property called "State". These "States" are all transient data which means they are available only for one instant of your application which means once you restart your application these states will be lost. Also we should not try to create a new PhoneApplicationService instead we must try to use the service from the current instant. Which can be retrieved using this code:

PhoneApplicationService.Current.State

Now, lets look how can we really use it in our sample.

PhonePageTwo add this code:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    PhoneApplicationService.Current.State["Text"] = txtBox.Text;
} 
private void Border_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
    NavigationService.GoBack();
}

PhonePageOne add this code:

private void LayoutRoot_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
 NavigationService.Navigate(new Uri("/PhonePageTwo.xaml", UriKind.Relative));
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    if(PhoneApplicationService.Current.State.ContainsKey("Text"))
        txtBlock.Text = (string)PhoneApplicationService.Current.State["Text"];
}

4. Using NextPage intance: Whenever we call "Navigate" using a "/PageOne.xaml" or "/PageTwo.xaml" the OnNavigatedFrom method in current page is called with event arguments with a  Uri property indicating other page and a Content property of type that page (Navigating to) . After that OnNavigatedTo of other page will be called with same arguments. So we have an opportunity to fix the set the value for next page prior to navigating to it. Just take a look at the sample code:

PageTwo add this code:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    if (e.Content is PageOne)
    {
        (e.Content as PageOne).txtBlock.Text = txtBox.Text;
    }
} 
private void Border_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
    NavigationService.GoBack();
}

PageOne add this code: (Basically no need to do any thing just use this)

private void LayoutRoot_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
 NavigationService.Navigate(new Uri("/PageTwo.xaml", UriKind.Relative));
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
 base.OnNavigatedTo(e);
}


Source Cod

Tuesday, August 2, 2011

Access Templated Child in Silverlight and Windows Phone 7



Accessing a templated child is way too simple in WPF but for SilverLight which is even being used in Windows Phone 7 needs a little extra work to the work being done. Well there are two ways to achieve it. I'll try to explain both of them one by one. Before getting into explanations of these methods we need a sample template to get a better picture.

A sample template for a ListBoxItem :


So, now when we have custom style :-)  we can start looking into the options to retrieve an element (myTextBox) from Style at run time.

First Approach
  1.  Make sure you have defined names for the items you are going to acess in your template let say it "myTextBox".
  2. Now you must have ListBoxItem for which you are going to find your TemplateChild lets say it "lbi".
After going through these initial check now use the following code to find element:

//Enforce Style to apply in case if it's not yet applied
lbi.ApplyTemplate();
FirstApproach(lbi);

void FirstApproach(ListBoxItem lbi)
{
    StackPanel stkTemplatedChild = VisualTreeHelper.GetChild((DependencyObject)lbi, 0) as StackPanel;
    TextBlock txtBlk = stkTemplatedChild.FindName("myTextBlk") as TextBlock;
    txtBlk.Text = "First Approach CLicked";
}

So, "txtBlk " is your desired element 

Second Approach:

This approach is to itrerate through all the elements in style's template. which can be done by using this code:

//Enforce Style to apply in case if it's not yet applied
lbi.ApplyTemplate();
SecondApproach(lbi);

void SecondApproach(ListBoxItem lbi)
{
    TextBlock templatedTextBlk;
    int childCount = VisualTreeHelper.GetChildrenCount((DependencyObject)lbi);
    for (int i = 0; i < childCount; i++)
    {
        DependencyObject childObj = VisualTreeHelper.GetChild(lbi, i);
        int subChild = VisualTreeHelper.GetChildrenCount(childObj);
        for (int n = 0; n < subChild; n++)
        {
            DependencyObject dpChild = VisualTreeHelper.GetChild(childObj, n);
            if (dpChild is TextBlock && (dpChild as TextBlock).Name == "myTextBlk")
            {
                templatedTextBlk = dpChild as TextBlock;
                templatedTextBlk.Text = "Second Approach Clicked";
                break;
            }
        }
    }
}
"templatedTextBx" is your result.

Third Approach (using helper function):  This approach may look catchy but it has some down sides. In this approach you have to iterate through VisualTree which could be a resource intensive. But this one is good if you have a inline template.

//Enforce Style to apply in case if it's not yet applied
lbi.ApplyTemplate();
TextBlock txtbx = FindVisualChildByType(lbi, "myTextBlk");
if (txtbx != null)
    txtbx.Text = "Third Approach Clicked";

T FindVisualChildByType(DependencyObject element, String name) where T : class     
{
    if (element is T && (element as FrameworkElement).Name == name)
        return element as T;
    int childcount = VisualTreeHelper.GetChildrenCount(element);
    for (int i = 0; i < childcount; i++)
    {
        T childElement = FindVisualChildByType(VisualTreeHelper.GetChild(element, i), name);
        if (childElement != null)
            return childElement;
    }
    return null;
}
So, txtbx is your desired result.
Source Code