Gustavo's profilementasBlogListsSkyDrive Tools Help

Blog


    November 24

    ItemsFeed

    Here's my proposal to break the limitations of current data/web feeds formats

    • Simplicity
    • Structured/Unstructured
    • Relational
    • Search and Filter friendly
    • Templating and DataBinding friendly

    Concepts:

    • ItemsFeed - is a data/web format (like RSS/Atom), a result from a query
    • Item - can be an image, memo, blog entry, news story, contact, document, ...whatever
    • Collection - a group of similar items, has a schema (item properties), may have a template (item look&feel)

    <ItemsFeed Version="1.0">

      <Collection Name="">

        <Collection.Schema>

          <!--

          Types: Text, Number, Date, Bytes, Links

          Formats (samples): Text (mask), Number (D2), Date (dddd, dd MMMM yyyy HH:mm), Bytes (xml/jpg/pdf), Links (File/HTTP/CollectionName[ItemID])

          IsFilter: True/False

          -->

          <Property Name="" Type="" Format="" IsFilter="" />

        </Collection.Schema>

        <Collection.Template>

          <!--

          Samples: xaml, html

          -->

        </Collection.Template>

        <!--

        ID: ULong/Guid

        -->

        <Item ID="" Title="" Description="" Date="" State="" Author="">

          <Property Name=""></Property>

          <!--

          <Property Name="">

            <Link></Link>

            <Link></Link>

            <Link></Link>

          </Property>

          -->

        </Item>

      </Collection>

    </ItemsFeed>

    November 15

    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

    }

    November 14

    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; }

    }

    November 03

    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; }

    }

    October 10

    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

    June 27

    UX Guidelines

    Some User eXperience guidelines.
     
     
     
     
    June 21

    User eXperience Kit

    UXKit (source code + samples + extras) is a small library with basic elements to archive a better user experience on Microsoft Silverlight 3.0 applications.
     
    The three fundamental concepts in user experiences:
     
    • Motion Graphics
    • Reader & Content
    • Workflow

    Features:

    • UIElement Extensions (Move, Zoom, Spin, Fade, Forces, Focus, Glow, Color, Manipulations)
    • Slides (custom transitions)
    • Ticker (see news crawlers)
    • Waves (fractal animations)
    • Chars (text effects)
    • LinkedBlock + Text/ContentFlow (see NY Times Reader, WPF FlowDocument)
    • Effects (ColorTone, ChromaKey)
    Note: A few util code (included in assembly) was obtained from some SL communities.
     
     
     
     
     
     
     
     
     
     
    January 25

    Silverlight Motion eXtensions

    Extension methods to extend any Silverlight FrameworkElement. With Motion eXtensions you can compose animations/behaviors using the "Builder pattern", writing short and simple code.
     
    Extensions:
     
    // Overview, download link at end of post

    public static class MotionExtensions

    {

        public static void MotionEnable(this FrameworkElement source)

     

        public static FrameworkElement Sleep(this FrameworkElement source, double duration);

     

        public static FrameworkElement Add(this FrameworkElement source, Panel panel);

        public static FrameworkElement Remove(this FrameworkElement source);

     

        public static FrameworkElement Show(this FrameworkElement source);

        public static FrameworkElement Hide(this FrameworkElement source);

     

        public static FrameworkElement Fade(this FrameworkElement source, double opacity, double duration);

        public static FrameworkElement Fade(this FrameworkElement source, double opacity, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement Move(this FrameworkElement source, double x, double y, double duration);

        public static FrameworkElement Move(this FrameworkElement source, double x, double y, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement Zoom(this FrameworkElement source, double scale, double duration);

        public static FrameworkElement Zoom(this FrameworkElement source, double scale, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement Spin(this FrameworkElement source, double angle, double duration);

        public static FrameworkElement Spin(this FrameworkElement source, double angle, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement Push(this FrameworkElement source, double x, double duration);

        public static FrameworkElement Push(this FrameworkElement source, double x, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement Slice(this FrameworkElement source, double y, double duration);

        public static FrameworkElement Slice(this FrameworkElement source, double y, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement FlipH(this FrameworkElement source, double scale, double duration);

        public static FrameworkElement FlipH(this FrameworkElement source, double scale, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement FlipV(this FrameworkElement source, double scale, double duration);

        public static FrameworkElement FlipV(this FrameworkElement source, double scale, double duration, double acceleration, double deceleration);

     

        public static FrameworkElement Action(this FrameworkElement source, ActionHandler function);

     

        public static void Begin(this FrameworkElement source);

     

        public static void SetOpacity(this FrameworkElement source, double opacity);

        public static double GetOpacity(this FrameworkElement source);

        public static void SetTranslation(this FrameworkElement source, double x, double y);

        public static Point GetTranslation(this FrameworkElement source);

        public static void SetRotation(this FrameworkElement source, double angle);

        public static double GetRotation(this FrameworkElement source);

        public static void SetScale(this FrameworkElement source, double sx, double sy);

        public static Size GetScale(this FrameworkElement source);

    }

     
    Samples:
     

    // Sample 1

    Rectangle rect = new Rectangle();

    rect.Fill = new SolidColorBrush(Color.FromArgb(128, 255, 0, 0));

    rect.Width = 100;

    rect.Height = 100;

     

    rect.MotionEnable(); 

    rect.SetTranslation(100, 100);

     

    rect.Add(MyPanel).Spin(90, 0.5).Move(200, 200, 0.25).Zoom(2, 0.25).Remove().Begin();

    rect.Sleep(0.75).Fade(0.0, 0.25).Begin();

     

    // Sample 2

    this.FlipH(0, 0.25).Action(MyAction).FlipH(1, 0.25).Begin();

     

    void MyAction(FrameworkElement element)

    {

        // Change element

    }

     

    // Sample 3

    this.Push(-50, 0.25, 0.0, 0.5).Push(200, 0.25, 0.5, 0.0).Remove().Begin();

     
    Notes:
     
    • RenderTransform, RenderTransformOrigin, Resources and Tag properties of element will be used
    • .Begin() must to be always at end of behavior functions
    • Use .MotionEnable() on element creation (or constructor) to avoid transform instance lost during events
    • You can easily convert (port) this code to WPF

    Download Here

    January 03

    HTML Helpers based on DCB

    Website base structure HTML Helpers for ASP.NET or ASP.NET MVC.
     
     
     
    Note: Behaviors requires jQuery, Microsoft is looking to make it part of their official development platform.
     

    Download Here

    January 01

    Introducing Design-Content-Behavior (DCB)

    Design-Content-Behavior (DCB) is an architectural software pattern to split "View" of Model-View-Controller (MVC) in three layers.
    This architecture isolates the fundamental areas of “User Experience".
     

    Design
    Look and Feel (states, styles, templates, ...)
    Content
    Interface/Contents (identification, layout, controls, text, media, ...)
    Behavior
    Content modification, events, transitions, internal/external Calls, ...

    March 18

    Silverlight Layers

    Looking for Bevel, Glow, Shadow, Reflection and Blur effects for Silverlight?! Not the perfect solution but you can do some Photoshop like effects on Silverlight by using pure vector graphics.

    You can compose, adjust parameters and.. also modify source code to your needs.
     
    Includes:
    • BevelRectangle, InnerGlowRectangle, InnerShadowRectangle, OuterGlowRectangle, OuterShadowRectangle, ReflectionRectangle
    • BevelEllipse, InnerGlowEllipse, InnerShadowEllipse, OuterGlowEllipse, OuterShadowEllipse, ReflectionEllipse
    • OuterGlowTextBlock, OuterShadowTextBlock, ReflectionTextBlock
    • BlurImage
    Compose Notes:
    • Outer effects (before)
    • Bevel, Inner and Reflection effects (after)

    SilverlightLayers

    Developed for Silverlight 2. Download Here

    March 02

    Unreleased Projects

    You can download some unreleased projects and some GotDotNet (closed) projects on my Public Folder.
     
    Includes:
    • mentas Ribbon
    • PhotoFilter
    • PhotoEffects
    • mentas Gaming
    • WPF PieMenu
    • Render .NET
    October 06

    XAML CoverFlow Layout (Part III)

    This example show how to make an iTunes like "CoverFlow" layout animation in XAML (Silverlight/WPF).

    Code samples don't show reflection of elements. You can make it easily with a copy of CoverFlow canvas (with some transformations and opacity). Don't make reflection of each element.. Make reflection of whole "list" to do a correct reflection.

    Silverlight Coverflow sample (Download):

    XAML CoverFlow Layout (Part II)

    This example show how to make an iTunes like "CoverFlow" layout animation in XAML (Silverlight/WPF).

    Notes:

    ·         This was written to WPF, can easily converted to Silverlight!

    ·         Underline values are width of element

    ·         You can set animation duration and perspective of elements

    ·         Perspective value and height of element are related

    CoverFlow Layout (C#)

    private void SelectCover(int index)

    {

        // Setup

        double coverwidth = 100;

        double coverwidth2 = coverwidth / 2;

        double center = (coverflowcontrol.ActualWidth - coverwidth) / 2;

     

        double perspectivetop = 25;

        double perspectivebotton = 10;

        double scaley = 0.8;

        double scalex = scaley * (1.0 - perspectivetop / coverwidth);

        double offset = coverwidth * 0.8;

     

        // Layout

        for (int i = 0; i < coverflowcontrol.Children.Count; i++)

        {

            Canvas cover = (Canvas)coverflowcontrol.Children[i];

     

            if (i < index)

            {

                Canvas.SetZIndex(cover, i);

     

                Storyboard sb = (Storyboard)cover.Resources[cover.Name + "_anim"];

                ((DoubleAnimation)sb.Children[0]).To = scalex;

                ((DoubleAnimation)sb.Children[1]).To = scaley;

                ((DoubleAnimation)sb.Children[2]).To = -perspectivebotton;

                ((DoubleAnimation)sb.Children[3]).To = center - (offset + ((index - 1) - i) * coverwidth2);

                ((PointAnimation)sb.Children[4]).To = new Point(0, 0);

                ((PointAnimation)sb.Children[5]).To = new Point(coverwidth, perspectivetop);

                sb.Begin(cover);

            }

            else if (i > index)

            {

                int ii = (i - index - 1);

     

                Canvas.SetZIndex(cover, (coverflowcontrol.Children.Count - 1) - ii);

     

                Storyboard sb = (Storyboard)cover.Resources[cover.Name + "_anim"];

                ((DoubleAnimation)sb.Children[0]).To = scalex;

                ((DoubleAnimation)sb.Children[1]).To = scaley;

                ((DoubleAnimation)sb.Children[2]).To = perspectivebotton;

                ((DoubleAnimation)sb.Children[3]).To = center + (offset + ii * coverwidth2);

                ((PointAnimation)sb.Children[4]).To = new Point(0, perspectivetop);

                ((PointAnimation)sb.Children[5]).To = new Point(coverwidth, 0);

                sb.Begin(cover);

            }

            else

            {

                Canvas.SetZIndex(cover, coverflowcontrol.Children.Count);

     

                Storyboard sb = (Storyboard)cover.Resources[cover.Name + "_anim"];

                ((DoubleAnimation)sb.Children[0]).To = 1;

                ((DoubleAnimation)sb.Children[1]).To = 1;

                ((DoubleAnimation)sb.Children[2]).To = 0;

                ((DoubleAnimation)sb.Children[3]).To = center;

                ((PointAnimation)sb.Children[4]).To = new Point(0, 0);

                ((PointAnimation)sb.Children[5]).To = new Point(coverwidth, 0);

                sb.Begin(cover);

            }

        }

    }

    XAML CoverFlow Layout (Part I)

    This example show how to make an iTunes like "CoverFlow" layout animation in XAML (Silverlight/WPF).

    Notes:

    ·         This was written to WPF, can easily convert to Silverlight!

    ·         Underline values are width of element

    ·         You can set animation duration and perspective of elements

    ·         Perspective value and height of element are related

    Cover Element (XAML)

    <!--CoverFlow Control (List)-->

    <Canvas Name="coverflowcontrol">

    (...)

    <!--CoverFlow Element-->

    <Canvas Name="coverXPTO" RenderTransformOrigin="0.5,0.5" Width="100" Height="100" Background="Black">

        <Canvas.Resources>

            <Storyboard x:Key="coverXPTO_anim">

                <DoubleAnimation To="1" Duration="0:0:0.2" Storyboard.TargetName="coverXPTO" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" />

                <DoubleAnimation To="1" Duration="0:0:0.2" Storyboard.TargetName="coverXPTO" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" />

                <DoubleAnimation To="0" Duration="0:0:0.2" Storyboard.TargetName="coverXPTO" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(SkewTransform.AngleY)" />

                <DoubleAnimation To="0" Duration="0:0:0.2" Storyboard.TargetName="coverXPTO" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(TranslateTransform.X)" />

                <PointAnimation To="0,0" Duration="0:0:0.2" Storyboard.TargetName="coverXPTO" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(LineSegment.Point)" />

                <PointAnimation To="100,0" Duration="0:0:0.2" Storyboard.TargetName="coverXPTO" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(LineSegment.Point)" />

            </Storyboard>

        </Canvas.Resources>

        <Canvas.RenderTransform>

            <TransformGroup>

                <ScaleTransform ScaleX="1" ScaleY="1" />

                <SkewTransform AngleX="0" AngleY="0" />

                <TranslateTransform X="0" Y="0" />

            </TransformGroup>

        </Canvas.RenderTransform>

        <Canvas.Clip>

            <PathGeometry>

                <PathFigure StartPoint="0,100" IsClosed="True">

                    <PathFigure.Segments>

                        <LineSegment Point="0,0"/>

                        <LineSegment Point="100,0"/>

                        <LineSegment Point="100,100"/>

                    </PathFigure.Segments>

                </PathFigure>

            </PathGeometry>

        </Canvas.Clip>

        <!--Child Elements (Image, Text, etc...)-->

    </Canvas>

    (...)

    </Canvas>