Gustavo 的个人资料mentas日志列表SkyDrive 工具 帮助
11月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="" Label="">

    <Collection.Schema>

      <!--

      Types: Boolean, 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="" Label="" Type="" Format="" IsFilter="" />

    </Collection.Schema>

    <Collection.Template>

      <!--

      Samples: xaml, html

      -->

    </Collection.Template>

    <!--

    ID: ULong/Guid

    -->

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

      <PropertyName></PropertyName>

      <!--

      <PropertyName>

        <Link></Link>

        <Link></Link>

        <Link></Link>

      </PropertyName>

      -->

    </Item>

  </Collection>

</ItemsFeed>

11月21日

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
11月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

}

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

}

11月3日

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

}