Profilo di GustavomentasBlogElenchiSkyDrive Strumenti Guida

Gustavo Arranhado

Professione
Località
Cartelle pubbliche
21 novembre

APDC 2009

Last week my team has been working for APDC 2009 congress. Microsoft Silverlight and Microsoft Surface has been used to create main event experiences.
 
Here's a resume...
 
Silverlight 3 (powered by FutureBox):
  • Event program
  • Twitter messages
  • 25 years memorial
  • Live streaming
 
  • APDC 25 years timeline (photo gallery and editions).
 
Developed by VIATECLA
15 novembre

NavigableDynamicItem (Part II)

A navigable version of DynamicItem. Now you can define forward/backward behaviors.
 

NavigableDynamicItem.cs

public class NavigableDynamicItem : Control

{

    private object temp_data = null;

 

    public NavigableDynamicItem()

    {

        this.DefaultStyleKey = typeof(NavigableDynamicItem);

    }

 

    public override void OnApplyTemplate()

    {

        base.OnApplyTemplate();

 

        FrameworkElement root = (FrameworkElement)GetTemplateChild("LayoutRoot");

        if (root == null)

            throw new Exception("'LayourRoot' element not found.");

 

        ((VisualStateGroup)VisualStateManager.GetVisualStateGroups(root)[0]).CurrentStateChanged += new EventHandler<VisualStateChangedEventArgs>(DynamicItem_CurrentStateChanged);

 

        VisualStateManager.GoToState(this, "ForwardEnter", false);

    }

 

    private void DynamicItem_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)

    {

        if (e.NewState.Name == "ForwardLeave")

        {

            DispatcherTimer delay = new DispatcherTimer() { Interval = EnterDelay };

            delay.Tick += delegate

            {

                DataContext = temp_data;

                temp_data = null;

 

                VisualStateManager.GoToState(this, "ForwardEnter", false);

                delay.Stop();

                delay = null;

            };

            delay.Start();

        }

        else if (e.NewState.Name == "ForwardEnter" && DataContext != null)

            VisualStateManager.GoToState(this, "Normal", true);

 

        if (e.NewState.Name == "BackwardLeave")

        {

            DispatcherTimer delay = new DispatcherTimer() { Interval = EnterDelay };

            delay.Tick += delegate

            {

                DataContext = temp_data;

                temp_data = null;

 

                VisualStateManager.GoToState(this, "BackwardEnter", false);

                delay.Stop();

                delay = null;

            };

            delay.Start();

        }

        else if (e.NewState.Name == "BackwardEnter" && DataContext != null)

            VisualStateManager.GoToState(this, "Normal", true);

    }

 

    public void ChangeDataContextForward(object data)

    {

        temp_data = data;

 

        DispatcherTimer delay = new DispatcherTimer() { Interval = LeaveDelay };

        delay.Tick += delegate

        {

            VisualStateManager.GoToState(this, "ForwardLeave", DataContext != null);

            delay.Stop();

            delay = null;

        };

        delay.Start();

    }

    public void ChangeDataContextBackward(object data)

    {

        temp_data = data;

 

        DispatcherTimer delay = new DispatcherTimer() { Interval = LeaveDelay };

        delay.Tick += delegate

        {

            VisualStateManager.GoToState(this, "BackwardLeave", DataContext != null);

            delay.Stop();

            delay = null;

        };

        delay.Start();

    }

 

    [Category("NavigableDynamicItem")]

    public TimeSpan EnterDelay { get; set; }

    [Category("NavigableDynamicItem")]

    public TimeSpan LeaveDelay { get; set; }

}

NavigableDynamicItem (Part I)

A navigable version of DynamicItem. Now you can define forward/backward behaviors.
 

Generic.xaml

<Style TargetType="local:NavigableDynamicItem">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="local:NavigableDynamicItem">

                <Border x:Name="LayoutRoot"

                    Background="{TemplateBinding Background}"

                    BorderBrush="{TemplateBinding BorderBrush}"

                    BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">

                    <VisualStateManager.VisualStateGroups>

                        <VisualStateGroup x:Name="TransitionStates">

                            <VisualStateGroup.Transitions>

                                <VisualTransition GeneratedDuration="00:00:00.5000000"/>

                                <VisualTransition GeneratedDuration="00:00:00" To="ForwardEnter"/>

                                <VisualTransition GeneratedDuration="00:00:00" To="BackwardEnter"/>

                            </VisualStateGroup.Transitions>

                            <VisualState x:Name="Normal"/>

                            <VisualState x:Name="ForwardEnter"/>

                            <VisualState x:Name="ForwardLeave"/>

                            <VisualState x:Name="BackwardEnter"/>

                            <VisualState x:Name="BackwardLeave"/>

                        </VisualStateGroup>

                    </VisualStateManager.VisualStateGroups>

                    <TextBlock Text="{Binding }" HorizontalAlignment="Center" VerticalAlignment="Center" />

                </Border>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>

Ticker

You can use this panel as ItemsPanelTemplate on ItemsControl, ListBox, ...
Note: For a better control over delta FPS use a Storyboard instead DispatcherTimer.
 

public class Ticker : Canvas

{

    public static readonly DependencyProperty DelayProperty;

    public static readonly DependencyProperty DeltaProperty;

 

    private double pos = 0;

 

    static Ticker()

    {

        DelayProperty = DependencyProperty.Register("Delay", typeof(TimeSpan), typeof(Ticker), new PropertyMetadata(TimeSpan.Zero));

        DeltaProperty = DependencyProperty.Register("Delta", typeof(double), typeof(Ticker), new PropertyMetadata(2.0));

    }

 

    public Ticker()

        : base()

    {

        ClipToBounds = true;

 

        Loaded += new RoutedEventHandler(Ticker_Loaded);

    }

 

    public void Ticker_Loaded(object sender, RoutedEventArgs e)

    {

        foreach (FrameworkElement fe in Children)

        {

            pos = ActualWidth;

            Canvas.SetLeft(fe, ActualWidth);

        }

 

        DispatcherTimer delay_timer = new DispatcherTimer() { Interval = Delay };

        delay_timer.Tick += delegate

        {

            DispatcherTimer delta_timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(10) };

            delta_timer.Tick += delegate

            {

                foreach (FrameworkElement fe in Children)

                {

                    pos -= Delta;

                    if (pos + fe.ActualWidth < 0)

                        pos = ActualWidth;

 

                    Canvas.SetLeft(fe, pos);

                }

            };

            delta_timer.Start();

 

            delay_timer.Stop();

        };

        delay_timer.Start();

    }

 

    [Category("Ticker")]

    public TimeSpan Delay

    {

        get { return (TimeSpan)GetValue(DelayProperty); }

        set { SetValue(DelayProperty, value); }

    }

    [Category("Ticker")]

    public double Delta

    {

        get { return (double)GetValue(DeltaProperty); }

        set { SetValue(DeltaProperty, value); }

    }

}

WPF/SL binding converters (Part III)

Plain text and image extraction from HTML...
 

public class TextConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        return Regex.Replace((string)value, @"<[^>]*>", string.Empty).Trim();

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    #endregion

}

 

public class ImageConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        MatchCollection matches = Regex.Matches((string)value, "src=(?:\"|\')?(?<imgSrc>[^>]*[^/].(?:jpg|png))(?:\"|\')?");

 

        if (matches.Count > 0)

        {

            if (parameter != null)

                return matches[int.Parse((string)parameter)].Groups[1].Value;

            else

                return matches[0].Groups[1].Value;

        }

 

        return "";

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    #endregion

}

WPF/SL binding converters (Part II)

XmlDataProvider (Text, Number and DateTime) sorting...
 

public class TextSortConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        if (value != null)

        {

            string[] args = ((string)parameter).Split(' ');

 

            ICollection col = (ICollection)value;

 

            List<string> aux = null;

 

            if (args.Length == 2 && args[1] == "desc")

            {

                aux = (from item in col.Cast<XmlElement>()

                       orderby item[args[0]].InnerText descending

                       select item.InnerXml).ToList();

            }

            else

            {

                aux = (from item in col.Cast<XmlElement>()

                       orderby item[args[0]].InnerText

                       select item.InnerXml).ToList();

            }

 

            int i = 0;

            foreach (XmlElement e in col)

            {

                e.InnerXml = aux[i];

                i++;

            }

        }

 

        return value;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    #endregion

}

 

public class NumericSortConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        if (value != null)

        {

            string[] args = ((string)parameter).Split(' ');

 

            ICollection col = (ICollection)value;

 

            List<string> aux = null;

 

            if (args.Length == 2 && args[1] == "desc")

            {

                aux = (from item in col.Cast<XmlElement>()

                       orderby double.Parse(item[args[0]].InnerText.Replace(".", ",")) descending

                       select item.InnerXml).ToList();

            }

            else

            {

                aux = (from item in col.Cast<XmlElement>()

                       orderby double.Parse(item[args[0]].InnerText.Replace(".", ","))

                       select item.InnerXml).ToList();

            }

 

            int i = 0;

            foreach (XmlElement e in col)

            {

                e.InnerXml = aux[i];

                i++;

            }

        }

 

        return value;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    #endregion

}

 

public class DateTimeSortConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        if (value != null)

        {

            string[] args = ((string)parameter).Split(' ');

 

            ICollection col = (ICollection)value;

 

            List<string> aux = null;

 

            if (args.Length == 2 && args[1] == "desc")

            {

                aux = (from item in col.Cast<XmlElement>()

                       orderby DateTime.Parse(item[args[0]].InnerText) descending

                       select item.InnerXml).ToList();

            }

            else

            {

                aux = (from item in col.Cast<XmlElement>()

                       orderby DateTime.Parse(item[args[0]].InnerText)

                       select item.InnerXml).ToList();

            }

 

            int i = 0;

            foreach (XmlElement e in col)

            {

                e.InnerXml = aux[i];

                i++;

            }

        }

 

        return value;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    #endregion

}

WPF/SL binding converters (Part I)

Number round and DateTime format...
 

public class NumericConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        if (!string.IsNullOrEmpty((string)value) && parameter != null)

        {

            string num = Math.Round(double.Parse(((string)value).Replace(".", ",")), int.Parse((string)parameter)).ToString();

 

            string[] dc = num.Split(',');

            int dc_num = 0;

            if (dc.Length == 2)

                dc_num = dc[1].Length;

 

            for (int i = dc_num; i < int.Parse((string)parameter); i++)

                num += "0";

 

            return num;

        }

        else

            return value;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    #endregion

}

 

public class DateTimeConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    {

        string dt = value.ToString();

 

        ulong aux = 0;

        if (ulong.TryParse(dt, out aux))

        {

            if (dt.Length == 8)

                return new DateTime(int.Parse(dt.Substring(0, 4)), int.Parse(dt.Substring(4, 2)), int.Parse(dt.Substring(6, 2))).ToString((string)parameter);

            else if (dt.Length == 10)

                return new DateTime(int.Parse(dt.Substring(0, 4)), int.Parse(dt.Substring(4, 2)), int.Parse(dt.Substring(6, 2)), int.Parse(dt.Substring(8, 2)), 0, 0).ToString((string)parameter);

            else if (dt.Length == 12)

                return new DateTime(int.Parse(dt.Substring(0, 4)), int.Parse(dt.Substring(4, 2)), int.Parse(dt.Substring(6, 2)), int.Parse(dt.Substring(8, 2)), int.Parse(dt.Substring(10, 2)), 0).ToString((string)parameter);

            else if (dt.Length == 14)

                return new DateTime(int.Parse(dt.Substring(0, 4)), int.Parse(dt.Substring(4, 2)), int.Parse(dt.Substring(6, 2)), int.Parse(dt.Substring(8, 2)), int.Parse(dt.Substring(10, 2)), int.Parse(dt.Substring(12, 2))).ToString((string)parameter);

            else

                return new DateTime(long.Parse(dt)).ToString((string)parameter);

        }

        else

            return DateTime.Parse(dt).ToString((string)parameter);

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

    {

        throw new NotImplementedException();

    }

 

    #endregion

}

14 novembre

DynamicItem

The ideia is something like "TransitionControl" concept (included in SL Toolkit), but using DataContext (Binding/Templating) and VisualStates.

DynamicItem is a Control and must to be templated and the entering/leaving behaviors defined using the three states (Normal, Enter, Leave). Call ChangeDataContext method to change data and invoke transition states.

If you need a composition between transition items, use two or more DynamicItem's (you can set an Enter/Leave delay time)... or simple prepare the Template and the DataContext to receive two items (new and old).

Generic.xaml

<Style TargetType="local:DynamicItem">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="local:DynamicItem">

                <Border x:Name="LayoutRoot"

                        Background="{TemplateBinding Background}"

                        BorderBrush="{TemplateBinding BorderBrush}"

                        BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">

                    <VisualStateManager.VisualStateGroups>

                        <VisualStateGroup x:Name="TransitionStates">

                            <VisualStateGroup.Transitions>

                                <VisualTransition GeneratedDuration="00:00:00.5000000"/>

                                <VisualTransition GeneratedDuration="00:00:00" To="Enter"/>

                            </VisualStateGroup.Transitions>

                            <VisualState x:Name="Normal"/>

                            <VisualState x:Name="Enter"/>

                            <VisualState x:Name="Leave"/>

                        </VisualStateGroup>

                    </VisualStateManager.VisualStateGroups>

                    <TextBlock Text="{Binding }" HorizontalAlignment="Center" VerticalAlignment="Center" />

                </Border>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>

 

DynamicItem.cs

public class DynamicItem : Control

{

    private object temp_data = null;

 

    public DynamicItem()

    {

        this.DefaultStyleKey = typeof(DynamicItem);

    }

 

    public override void OnApplyTemplate()

    {

        base.OnApplyTemplate();

 

        FrameworkElement root = (FrameworkElement)GetTemplateChild("LayoutRoot");

        if (root == null)

            throw new Exception("'LayourRoot' element not found.");

 

        ((VisualStateGroup)VisualStateManager.GetVisualStateGroups(root)[0]).CurrentStateChanged += new EventHandler<VisualStateChangedEventArgs>(DynamicItem_CurrentStateChanged);

 

        VisualStateManager.GoToState(this, "Enter", false);

    }

 

    private void DynamicItem_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)

    {

        if (e.NewState.Name == "Leave")

        {

            DispatcherTimer delay = new DispatcherTimer() { Interval = EnterDelay };

            delay.Tick += delegate

            {

                DataContext = temp_data;

                temp_data = null;

 

                VisualStateManager.GoToState(this, "Enter", false);

                delay.Stop();

                delay = null;

            };

            delay.Start();

        }

        else if (e.NewState.Name == "Enter" && DataContext != null)

            VisualStateManager.GoToState(this, "Normal", true);

    }

 

    public void ChangeDataContext(object data)

    {

        temp_data = data;

 

        DispatcherTimer delay = new DispatcherTimer() { Interval = LeaveDelay };

        delay.Tick += delegate

        {

            VisualStateManager.GoToState(this, "Leave", DataContext != null);

            delay.Stop();

            delay = null;

        };

        delay.Start();

    }

 

    [Category("DynamicItem")]

    public TimeSpan EnterDelay { get; set; }

    [Category("DynamicItem")]

    public TimeSpan LeaveDelay { get; set; }

}

03 novembre

Zoombox

Basic implementation of "Blendables Essentials Mix" concept for Silverlight.
 
Generic.xaml
 

<Style TargetType="local:Zoombox">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="local:Zoombox">

                <Canvas x:Name="Container">

                    <ContentPresenter>

                        <ContentPresenter.RenderTransform>

                            <TransformGroup>

                                <ScaleTransform x:Name="Zoom" />

                                <TranslateTransform x:Name="Pan" />

                            </TransformGroup>

                        </ContentPresenter.RenderTransform>

                    </ContentPresenter>

                </Canvas>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>

 
Zoombox.cs
 

public class Zoombox : ContentControl

{

    private Canvas container = null;

    private ScaleTransform zoom = null;

    private TranslateTransform pan = null;

 

    public Zoombox()

    {

        this.DefaultStyleKey = typeof(Zoombox);

 

        ZoomMargin = 10;

    }

 

    public override void OnApplyTemplate()

    {

        base.OnApplyTemplate();

 

        container = (Canvas)GetTemplateChild("Container");

        zoom = (ScaleTransform)GetTemplateChild("Zoom");

        pan = (TranslateTransform)GetTemplateChild("Pan");

    }

 

    public void ZoomTo(Rect rect)

    {

        rect.X = rect.X - ZoomMargin / 2;

        rect.Y = rect.Y - ZoomMargin / 2;

        rect.Width = rect.Width + ZoomMargin;

        rect.Height = rect.Height + ZoomMargin;

 

        double factor = Math.Min(container.ActualWidth / rect.Width, container.ActualHeight / rect.Height);

        zoom.ScaleY = zoom.ScaleX = factor;

 

        pan.X = (container.ActualWidth - rect.Width * factor) / 2 - rect.X * factor;

        pan.Y = (container.ActualHeight - rect.Height * factor) / 2 - rect.Y * factor;

    }

    public void ZoomTo(Rect rect, TimeSpan duration)

    {

        ZoomTo(rect, duration, null);

    }

    public void ZoomTo(Rect rect, TimeSpan duration, IEasingFunction func)

    {

        rect.X = rect.X - ZoomMargin / 2;

        rect.Y = rect.Y - ZoomMargin / 2;

        rect.Width = rect.Width + ZoomMargin;

        rect.Height = rect.Height + ZoomMargin;

 

        double factor = Math.Min(container.ActualWidth / rect.Width, container.ActualHeight / rect.Height);

 

        double panx = (container.ActualWidth - rect.Width * factor) / 2 - rect.X * factor;

        double pany = (container.ActualHeight - rect.Height * factor) / 2 - rect.Y * factor;

 

        Storyboard sb = new Storyboard();

 

        DoubleAnimation zoomx_anim = new DoubleAnimation() { To = factor, Duration = duration, EasingFunction = func };

        Storyboard.SetTarget(zoomx_anim, zoom);

        Storyboard.SetTargetProperty(zoomx_anim, new PropertyPath("ScaleX"));

 

        DoubleAnimation zoomy_anim = new DoubleAnimation() { To = factor, Duration = duration, EasingFunction = func };

        Storyboard.SetTarget(zoomy_anim, zoom);

        Storyboard.SetTargetProperty(zoomy_anim, new PropertyPath("ScaleY"));

 

        DoubleAnimation panx_anim = new DoubleAnimation() { To = panx, Duration = duration, EasingFunction = func };

        Storyboard.SetTarget(panx_anim, pan);

        Storyboard.SetTargetProperty(panx_anim, new PropertyPath("X"));

 

        DoubleAnimation pany_anim = new DoubleAnimation() { To = pany, Duration = duration, EasingFunction = func };

        Storyboard.SetTarget(pany_anim, pan);

        Storyboard.SetTargetProperty(pany_anim, new PropertyPath("Y"));

 

        sb.Children.Add(zoomx_anim);

        sb.Children.Add(zoomy_anim);

        sb.Children.Add(panx_anim);

        sb.Children.Add(pany_anim);

        sb.Begin();

    }

 

    public double ZoomCache

    {

        get

        {

            if (((UIElement)Content).CacheMode == null)

                return 0;

            else

                return ((BitmapCache)((UIElement)Content).CacheMode).RenderAtScale;

        }

        set

        {

            if (value == 0)

                ((UIElement)Content).CacheMode = null;

            else

                ((UIElement)Content).CacheMode = new BitmapCache() { RenderAtScale = value };

        }

    }

    public double ZoomMargin { get; set; }

}

10 ottobre

CollectionFlow

CollectionFlow is a CarouselCoverFlow, whatever (change it properties and get what you want) for Microsoft Silverlight 3.0. Unlike other samples, CollectionFlow inherit from ItemsControl, then you can use DataBinding / DataTemplate and change ItemsPanel (CollectionFlowPanel) properties.

Updated (11Oct2009):

  • ItemRelativeSize
  • UseRelativeSize

Updated (13Oct2009):

  • SelectedItem
  • Bugs correction

Download Here