Archive for the ‘ Silverlight ’ Category

OMG, Custom Silverlight Panels

Ok so the following doesn’t extend WrapPanel except to add the correct template for the ‘column’. Examples of completely custom panels can be found here and here.

public class WrapInColumnsPanel : WrapPanel
    {

        public readonly DependencyProperty NumberOfColumnsProperty =
            DependencyProperty.Register(
            "NumberOfColumns", typeof(Double),
            typeof(WrapInColumnsPanel), null);

        public double NumberOfColumns
        {
            get { return (double)GetValue(NumberOfColumnsProperty); }
            set { SetValue(NumberOfColumnsProperty, value); }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            for (int i = 0; i < Children.Count; i++)
            {
                Double DbCurrentChildPosition = (double)i + 1;
                if (DbCurrentChildPosition % NumberOfColumns == 0.0)
                {
                    //Child is in the last column
                    ContentPresenter cp = Children[i] as ContentPresenter;
                    cp.HorizontalAlignment = HorizontalAlignment.Right;
                    cp.ContentTemplate = App.Current.Resources["ContentGridDataTemplateRight"] as DataTemplate;
                    cp.Arrange(new Rect(new Point(0, 0), cp.DesiredSize));
                }
                else if (DbCurrentChildPosition == 1 || (DbCurrentChildPosition - 1) % NumberOfColumns == 0.0)
                {
                    //Child is in the first column
                    ContentPresenter cp = Children[i] as ContentPresenter;
                    cp.HorizontalAlignment = HorizontalAlignment.Right;
                    cp.ContentTemplate = App.Current.Resources["ContentGridDataTemplateLeft"] as DataTemplate;
                    cp.Arrange(new Rect(new Point(0, 0), cp.DesiredSize));
                }
                else
                {
                    //Child is in the centre
                    ContentPresenter cp = Children[i] as ContentPresenter;
                    cp.HorizontalAlignment = HorizontalAlignment.Right;
                    cp.ContentTemplate = App.Current.Resources["ContentGridDataTemplateCenter"] as DataTemplate;
                    cp.Arrange(new Rect(new Point(0, 0), cp.DesiredSize));
                }
            }
            return base.ArrangeOverride(finalSize);
        }
    }

How to Access Resources in an Assembly

new Uri("SilverlightApplication1;component/MyImage.png", UriKind.Relative)

Cross linked styles can be access in the same way!

<ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/SharedThemeAssembly;component/MyStyles.xaml"/>
            ...other ResourceDictionaries to merge in...
</ResourceDictionary.MergedDictionaries>

MVVM Light

MVVM Light databinds by placing a ViewModelLocator in the Application Resources. The ViewModelLocator exposes a property (which you create per ViewModel) that initializes and returns the ViewModel you wish to bind.

It has a behavior called EventToCommand which binds any UI event an ICommand.

It has a messenger class which allow ViewModels to publish and subscribe ‘messages’.

All the details are here

Silverlight MVVM Databinding for Blendability (View First)

Once you have a View (xaml interface design with no code behind), a ViewModel (class that contains the logic to connect the View and the Model) you’ll want to bind data to the controls.

The following sets the DataContext to the ViewModel





As this is in the XAML you will be able to view the results in Blend.

MVVM and Prism – The App, BootStrapper, Shell and Modules

Prism helps create a modular application using something called the Bootstrapper.  This can initiate the Shell (a UserControl that contains Regions where you can place your Modules) and also initiates the ModuleCatalog which manages you modules – opening, closing, positioning, etc.

In the App.xaml.cs change the Application_Startup to read:

<div id="_mcePaste">private void Application_Startup(object sender, StartupEventArgs e)</div>
<div id="_mcePaste">{</div>
<div id="_mcePaste">Bootstrapper b = new Bootstrapper();</div>
<div id="_mcePaste">b.Run();</div>
<div id="_mcePaste">}</div>
private void Application_Startup(object sender, StartupEventArgs e)
{
Bootstrapper b = new Bootstrapper();
b.Run();
}

In the Bootstapper you can initiate the RootVisual as the Shell and create a ModuleCatalog and add any modules.


namespace MVVM_Example
{
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
Shell shell = Container.Resolve();
Application.Current.RootVisual = shell;
return shell;
}

protected override Microsoft.Practices.Composite.Modularity.IModuleCatalog GetModuleCatalog()
{
ModuleCatalog catalog = new ModuleCatalog();
catalog.AddModule(typeof(ModuleA.ModuleA));
return catalog;
}
}
}

Each module is a separate project that can a number of Views with their ViewModels.

The module needs to be registered with a region.

namespace ModuleA
{
public class ModuleA : IModule
{
IRegionManager _regionManager;
IUnityContainer _container;

public ModuleA(IRegionManager regionManager, IUnityContainer container)
{
_regionManager = regionManager;
_container = container;
}

#region IModule Members

public void Initialize()
{
_regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.ModuleAView));

}

#endregion
}
}

Finding the Parent

I didn’t realise that getting to the parent FrameworkElement was so easy. This code came from the Silverlight.net Forum, I like to link but I’ve lost the post.

GetParent((FrameworkElement)this, typeof(Grid));
private FrameworkElement GetParent(FrameworkElement child, Type targetType)
        {
            object parent = child.Parent;
            if (parent != null)
            {
                if (parent.GetType() == targetType)
                {
                    return (FrameworkElement)parent;
                }
                else
                {
                    return GetParent((FrameworkElement)parent, targetType);
                }
            }
            return null;
        }

A better way to find the parent using the VisualTreeHelper found on the Silverlight forums:

public static class ControlFinder
    {
        public static T FindParent<T>(UIElement control) where T: UIElement
        {
            UIElement p = VisualTreeHelper.GetParent(control) as UIElement;
            if (p != null)
            {
                if (p is T)
                    return p as T;
                else
                    return ControlFinder.FindParent<T>(p);
            }
            return null;
        }
}

Page p = ControlFinder.FindParent<Page>(CurrentControl);

if(p != null)

{

      // here is your Page Control that in the parent chain 

}

Create a Storyboard Programatically

I’ve just created my first Storyboard outside of Blend so I thought I break down the code and save it for reference

            // Create a duration of .5 seconds.
            Duration duration = new Duration(TimeSpan.FromMilliseconds(500));

            //Create two DoubleAnimationsUsingKeyFrame and set their properties.
            DoubleAnimationUsingKeyFrames myDoubleAnimation1 = new DoubleAnimationUsingKeyFrames();
            myDoubleAnimation1.Duration = duration;

            //Create an EasingDoubleKeyFrame
            EasingDoubleKeyFrame WidthChange = new EasingDoubleKeyFrame();
            WidthChange.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(500));
            WidthChange.Value = DblHeight;
            CircleEase EsEase = new CircleEase();
            EsEase.EasingMode = EasingMode.EaseInOut;
            WidthChange.EasingFunction = EsEase;
            myDoubleAnimation1.KeyFrames.Add(WidthChange);

            Storyboard sb = new Storyboard();
            sb.Duration = duration;

            sb.Children.Add(myDoubleAnimation1);

            //I don't know why but Targets are set with a static method in the Storyboard class
            Storyboard.SetTarget(myDoubleAnimation1, AnimationTarget);
            Storyboard.SetTargetProperty(myDoubleAnimation1, new PropertyPath("(FrameworkElement.Width)"));

            return sb;