This is a migrated thread and some comments may be shown as answers.

Media Center like menu

3 Answers 141 Views
Carousel
This is a migrated thread and some comments may be shown as answers.
Phillip
Top achievements
Rank 1
Phillip asked on 17 Dec 2010, 04:27 PM
Hi,
I am using the carousel control to implement a media center like menu for my application. The main menu items should scroll vertically with the current item in the centre and the sub items should then appear below it and be chooseable. The priority is on easy keyboard navigation.

The problems I am facing are:

1) Styling the carousel seems to be incredibly difficult. Just having the main menu item description with a list of sub items is even difficult to do. Adding additional elements to the data template seems to stop the sub items from rendering.

2) Keyboard navigation does not work correctly. I'd like the main menu to scroll on Up / Down and the sub menu to scroll on Left / Right. Unfortunately, only the currently focused carousel panel will scroll and it then scrolls on all arrow key presses.

The control seems to have such a steep learning curve that I'm tempted to ditch it and write my own custom control - albeit without some of the nice scrolling effects that your control brings.

I've attached my attempt below, it is based on a sample I saw on this site. Any help would be appreciated.

    <UserControl.Resources>
        <Path
          x:Key="horizontalPath"
          Stretch="None"
          Opacity="1"
          Data="M0,0 C0,0 0,800 0,800"
          Stroke="#FFB4B4B4"
          StrokeThickness="4">
        </Path>
        <DataTemplate DataType="{x:Type local:Message}">
                <telerik:CarouselScrollViewer CanContentScroll="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<!-- putting in a header here stops the child panel from rendering correctly -->
                    <telerik:RadCarouselPanel Loaded="RadCarouselPanel_Loaded" CanVerticallyScroll="False" TopContainerChanged="RadCarouselPanel_TopContainerChanged_1">
                        <Button Content="menu1"/>
                        <Button Content="menu2"/>
                        <Button Content="menu3"/>
                        <Button Content="menu4"/>
                        <Button Content="menu5"/>
                        <Button Content="menu6"/>
                    </telerik:RadCarouselPanel>
            </telerik:CarouselScrollViewer>
        </DataTemplate>
        <Style TargetType="{x:Type telerik:CarouselItem}">
            <Setter Property="MaxHeight" Value="1000"/>
            <Setter Property="MaxWidth" Value="1000"/>
            <Setter Property="Height" Value="200"/>
            <Setter Property="Width" Value="400"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="telerik:CarouselItem">
                        <Border x:Name="mainBorder">
                            <Border Opacity="1" BorderBrush="#3F000000" BorderThickness="1,1,1,1" CornerRadius="5,5,5,5" Margin="10,10,10,10" x:Name="CarouselItemInnerBorder" SnapsToDevicePixels="True">
                                <Border.Background>
                                    <LinearGradientBrush EndPoint="101,462" StartPoint="101,13" MappingMode="Absolute">
                                        <GradientStop Color="#FF2C3A68" Offset="0"/>
                                        <GradientStop Color="#FF000000" Offset="1"/>
                                        <GradientStop Color="#FF0F224C" Offset="0.045"/>
                                        <GradientStop Color="#FF000000" Offset="0.0451"/>
                                    </LinearGradientBrush>
                                </Border.Background>
                                <ContentPresenter IsHitTestVisible="True" />
                            </Border>
                        </Border>
                        <ControlTemplate.Triggers>
<!-- IsSelected does not appear to fire -->
                            <Trigger Property="IsSelected" Value="True" >
                                <Setter TargetName="CarouselItemInnerBorder" Property="Background">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="108,472" StartPoint="108,23" MappingMode="Absolute">
                                            <GradientStop Color="#FF344B97" Offset="0"/>
                                            <GradientStop Color="#FF000000" Offset="1"/>
                                            <GradientStop Color="#FF233F7E" Offset="0.045"/>
                                            <GradientStop Color="#FF000000" Offset="0.0451"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid>
        <telerik:RadCarousel x:Name="radCarousel" AutoGenerateDataPresenters="False" Loaded="radCarousel_Loaded" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
            <telerik:RadCarousel.ItemsPanel>               
                <ItemsPanelTemplate>
                    <telerik:RadCarouselPanel x:Name="radCarouselPanel" IsScalingEnabled="True" IsOpacityEnabled="False" CanHorizontallyScroll="False" TopContainerChanged="RadCarouselPanel_TopContainerChanged" >                       
                    </telerik:RadCarouselPanel>
                </ItemsPanelTemplate>
            </telerik:RadCarousel.ItemsPanel>
        </telerik:RadCarousel>
    </Grid>
</UserControl>

3 Answers, 1 is accepted

Sort by
0
Vanya Pavlova
Telerik team
answered on 20 Dec 2010, 05:39 PM
Hi Phillip,

 
I have prepared an example for you that contains a part of your code snippet. However I am not quite sure what happened behind the following RadCarouselPanel_TopContainerChanged event as well as the defined DataTemplate that uses CarouselScrollViewer and where it has been set.

Feel free to modify the attached example and sent it back to me via support ticket if needed.

Regards,
Vanya Pavlova
the Telerik team
Browse the videos here>> to help you get started with RadControls for WPF
0
Phillip
Top achievements
Rank 1
answered on 20 Jan 2011, 01:43 PM
Thanks but that doesn't really help me with my problem. Do you have a sample of the carousel where each carousel item in the list has a sublist of items and both are keyboard navigable?
The keyboard navigation is a particular problem for me with this control. It behaves the same whether Up / Left or Right / Down are pressed. I need the Up / Down to control the top list and Left / Right to move the sublist. Also, the keyboard navigation does not work until an item is clicked and keyboard navigation does not appear to update the selected item.

I'd appreciate a quick response to help us continue our evaluation of the Telerik controls.

EDIT: I've made a little progress but keyboard navigation is still messed up... I'm not sure if the RadCarousel will be suitable for this task as the navigation seems to be pretty poor. I've got the outer and inner carousels populating (except the inner carousel should be horizontal, not vertical) but navigating using the arrow keys yields strange results. I appreciate any help with this.

MainWindow.xaml:

<Window
    xmlns:sampleData="clr-namespace:Expression.Blend.SampleData.SampleDataSource"
    x:Class="WpfApplication24.MainWindow"
    x:Name="Window"
    Title="MainWindow"
    Width="640" Height="480">
<Window.Resources>
        <Path
          x:Key="mainCarouselPath"
          Stretch="None"
          Opacity="1"
          Data="M0,0 C0,0 0,800 0,800"
          Stroke="#FFB4B4B4"
          StrokeThickness="4">
        </Path>
    </Window.Resources>
    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
        <telerik:RadCarousel  x:Name="radCarousel" ItemsSource="{Binding Collection}" AutoGenerateDataPresenters="False"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" SelectionChanged="radCarousel_SelectionChanged" Loaded="radCarousel_Loaded" PreviewMouseDown="Carousel_PreviewMouseDown" KeyUp="radCarousel_KeyUp">
            <telerik:RadCarousel.ItemTemplate>
                <DataTemplate>
                    <telerik:RadCarousel x:Name="innerCarousel" AutoGenerateDataPresenters="False"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" ItemsSource="{Binding Path=Children}" PreviewMouseDown="Carousel_PreviewMouseDown" KeyUp="radCarousel_KeyUp">
                        <telerik:RadCarousel.ItemsPanel>
                            <ItemsPanelTemplate>
                                <telerik:RadCarouselPanel x:Name="radCarouselPanel" IsScalingEnabled="True" IsOpacityEnabled="False" CanHorizontallyScroll="True" CanVerticallyScroll="false" Path="{StaticResource mainCarouselPath}" >
                                </telerik:RadCarouselPanel>
                            </ItemsPanelTemplate>
                        </telerik:RadCarousel.ItemsPanel>
                    </telerik:RadCarousel>
                </DataTemplate>
            </telerik:RadCarousel.ItemTemplate>
                <telerik:RadCarousel.ItemsPanel>              
                <ItemsPanelTemplate>
                    <telerik:RadCarouselPanel x:Name="radCarouselPanel" IsScalingEnabled="True" IsOpacityEnabled="False" CanHorizontallyScroll="False" Path="{StaticResource mainCarouselPath}" >                                              
                    </telerik:RadCarouselPanel>
                </ItemsPanelTemplate>               
            </telerik:RadCarousel.ItemsPanel>       
        </telerik:RadCarousel>
    </Grid>
</Window>

MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Telerik.Windows.Controls;
 
namespace WpfApplication24
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
            radCarousel.SelectedItem = radCarousel.Items[0];
            radCarousel.BringDataItemIntoView(radCarousel.Items[0]);
            // Insert code required on object creation below this point.
        }
 
        private void radCarousel_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangeEventArgs e)
        {
            ((RadCarousel)sender).BringDataItemIntoView(((RadCarousel)sender).SelectedItem);
        }
 
        /*private void Window_KeyUp(object sender, KeyEventArgs e)
        {
            int offset = 0;
            RadCarousel carousel = null;
 
            if (e.Key == Key.Up)
            {
                offset = -1;
                carousel = radCarousel;
                e.Handled = true;
            }
            else if (e.Key == Key.Down)
            {
                offset = 1;
                carousel = radCarousel;
                e.Handled = true;
            }
            else if (e.Key == Key.Left || e.Key == Key.Right)
            {
                if (e.Key == Key.Left)
                    offset = -1;
                else if (e.Key == Key.Right)
                    offset = 1;
 
                var panel = radCarousel.FindCarouselPanel();
                var i = (panel.ItemContainerGenerator.GetItemContainerGeneratorForPanel(panel)
                        .ContainerFromItem(radCarousel.CurrentItem));
                // Getting the ContentPresenter of myListBoxItem
                if (i != null)
                {
                    ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(i);
 
                    // Finding textBlock from the DataTemplate that is set on that ContentPresenter
                    DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
                    //carousel = (RadCarousel)myDataTemplate.FindName("innerCarousel", myContentPresenter); // why is this null?                                               
                    var carouselList = myContentPresenter.ChildrenOfType<RadCarousel>();
                    if (carouselList.Count > 0)
                        carousel = carouselList[0];
                }
                e.Handled = true;
            }
            if (carousel != null)
            {
                MoveCarousel(carousel, offset);
                //radCarousel.FindCarouselPanel().MoveBy(offset);
            }
        }*/
 
 
        private void Carousel_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            CarouselScrollViewer scrollViewer = FindChild<CarouselScrollViewer>((RadCarousel)sender, null);
            scrollViewer.Focus();
        }
 
 
        public static T FindChild<T>(DependencyObject parent, string childName)
           where T : DependencyObject
        {
            // Confirm parent and childName are valid.
            if (parent == null) return null;
 
 
            T foundChild = null;
 
 
            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                // If the child is not of the request child type child
                T childType = child as T;
                if (childType == null)
                {
                    // recursively drill down the tree
                    foundChild = FindChild<T>(child, childName);
 
 
                    // If the child is found, break so we do not overwrite the found child.
                    if (foundChild != null) break;
                }
                else if (!string.IsNullOrEmpty(childName))
                {
                    var frameworkElement = child as FrameworkElement;
                    // If the child's name is set for search
                    if (frameworkElement != null && frameworkElement.Name == childName)
                    {
                        // if the child's name is of the request name
                        foundChild = (T)child;
                        break;
                    }
                }
                else
                {
                    // child element found.
                    foundChild = (T)child;
                    break;
                }
            }
            return foundChild;
        }
 
 
        private childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is childItem)
                    return (childItem)child;
                else
                {
                    childItem childOfChild = FindVisualChild<childItem>(child);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
        }
 
        private void MoveCarousel(RadCarousel carousel, int offset)
        {
            if (offset != 0)
            {
                var items = carousel.Items;
                for (int n = 0; n < items.Count; n++)
                {
                    var item = items[n];
                    if (item == carousel.SelectedItem)
                    {
                        int index = n + offset;
                        if (index >= 0 && index < items.Count)
                        {
                            carousel.CurrentItem = items[index];
                            carousel.SelectedItem = items[index];
                            carousel.BringDataItemIntoView(items[index]);
                        }
                        break;
                    }
                }
 
            }
        }
 
        private void radCarousel_Loaded(object sender, RoutedEventArgs e)
        {
            //var panel = this.radCarousel.FindCarouselPanel();
 
           // panel.IsScalingEnabled = false;
//            panel.Path = (Path)this.Resources["mainCarouselPath"];       
        }
 
        private void radCarousel_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Up)
            {
                //radCarousel.Focus();
                CarouselScrollViewer scrollViewer = FindChild<CarouselScrollViewer>(radCarousel, null);
                scrollViewer.Focus();
                MoveCarousel(radCarousel, -1);
                e.Handled = true;
            }
            else if (e.Key == Key.Right)
            {
                //radCarousel.Focus();
                CarouselScrollViewer scrollViewer = FindChild<CarouselScrollViewer>(radCarousel, null);
                scrollViewer.Focus();
                MoveCarousel(radCarousel, 1);
                e.Handled = true;
            }
            else if (e.Key == Key.Left || e.Key == Key.Right)
            {
                var panel = radCarousel.FindCarouselPanel();
                var i = (panel.ItemContainerGenerator.GetItemContainerGeneratorForPanel(panel)
                        .ContainerFromItem(radCarousel.CurrentItem));
                // Getting the ContentPresenter of myListBoxItem
                RadCarousel innerCarousel = null;
                if (i != null)
                {
                    ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(i);
 
                    // Finding textBlock from the DataTemplate that is set on that ContentPresenter
                    DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
                    //carousel = (RadCarousel)myDataTemplate.FindName("innerCarousel", myContentPresenter); // why is this null?                                               
                    var carouselList = myContentPresenter.ChildrenOfType<RadCarousel>();
                    if (carouselList.Count > 0)
                    {
                        innerCarousel = carouselList[0];
                        //innerCarousel.Focus();
                        CarouselScrollViewer scrollViewer = FindChild<CarouselScrollViewer>(innerCarousel, null);
                        scrollViewer.Focus();
                    }
                }
                if (innerCarousel != null)
                {
                    if (e.Key == Key.Left)
                        MoveCarousel(innerCarousel, -1);
                    else if (e.Key == Key.Right)
                        MoveCarousel(innerCarousel, 1);
                    e.Handled = true;
                }
            }
        }
    }
}

SampleData.xaml.cs - Item class
public class Item : System.ComponentModel.INotifyPropertyChanged
{
    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
 
    public Item()
    {
        Children = new System.Collections.ObjectModel.ObservableCollection<String>();
        Children.Add(GetHashCode().ToString());
        Children.Add(GetHashCode().ToString());
        Children.Add(GetHashCode().ToString());
        Children.Add(GetHashCode().ToString());
        Children.Add(GetHashCode().ToString());
        Children.Add(GetHashCode().ToString());
    }
 
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
 
    private string _Property1 = string.Empty;
 
    public string Property1
    {
        get
        {
            return this._Property1;
        }
 
        set
        {
            if (this._Property1 != value)
            {
                this._Property1 = value;
                this.OnPropertyChanged("Property1");
            }
        }
    }
 
    public System.Collections.ObjectModel.ObservableCollection<String> Children
    {
        get;
        private set;
    }
 
}
0
Milan
Telerik team
answered on 27 Jan 2011, 05:47 PM

Hello Phillip,

RadCarousel contains a ScrollViewer control which will handle mouse and keyboard events. The logic that you are trying to implement is quite a special case and you will have to remove the ScrollViewer control to be able to achieve the desired result. 

I have attached a sample project which demonstrates a sample implementation. 



Regards,
Milan
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
Tags
Carousel
Asked by
Phillip
Top achievements
Rank 1
Answers by
Vanya Pavlova
Telerik team
Phillip
Top achievements
Rank 1
Milan
Telerik team
Share this question
or