web 2.0

Silverlight tabcontrol with scrollable tabItems

I ran into an issue where I had more tab items than could fit within the desired width of my tab control.  Instead of all the tab items appearing on a single line, they would wrap and create a multiline affect which I did not want.  I wanted the user to be able to scroll through the tab items if needed.  I did some checking to see if someone had built or customized the silverlight toolkit to support this but I did not find anything, so I decided to create a custom tabcontrol with scrollable items.  Below is a picture of the default tab control and my custom scrollable tabcontrol.  Note: I have only modified the "Top" layout for the tabcontrol so if someone wants to use one of the other layouts, they will have to update accordingly.

 

Here is the code for the custom scrollable tab control.

file: ScrollableTab.xaml.cs


 [StyleTypedProperty(Property = "TabLeftButtonTopStyle", StyleTargetType = typeof(RepeatButton)),
     StyleTypedProperty(Property = "TabRightButtonTopStyle", StyleTargetType = typeof(RepeatButton)),
     TemplatePart(Name = "TabLeftButtonTop", Type = typeof(RepeatButton)),
	 TemplatePart(Name = "TabRightButtonTop", Type = typeof(RepeatButton)),
     TemplatePart(Name = "TabScrollViewerTop", Type = typeof(ScrollViewer)),
     TemplatePart(Name = "TabPanelTop", Type = typeof(TabPanel))]
    public class SlidingTabControl : System.Windows.Controls.TabControl
    {
		private RepeatButton tabLeftButton;
		private RepeatButton tabRightButton;
        private ScrollViewer tabScrollViewer;
        private TabPanel tabPanelTop;
        private double currentHorizontalOffset = 0;
        private double maxHorizontalOffset = 0;

        /// 
        /// Tab Top Left Button style
        /// 
        public static readonly DependencyProperty TabLeftButtonTopStyleProperty = DependencyProperty.Register(
            "TabLeftButtonTopStyle",
            typeof(Style),
            typeof(SlidingTabControl),
            new PropertyMetadata(null));

        /// 
        /// Tab Top Left Button style
        /// 
        public static readonly DependencyProperty TabRightButtonTopStyleProperty = DependencyProperty.Register(
            "TabRightButtonTopStyle",
            typeof(Style),
            typeof(SlidingTabControl),
            new PropertyMetadata(null));

        /// 
        /// Initializes a new instance of the  class.
        /// 
        public SlidingTabControl()
        {
            this.DefaultStyleKey = typeof(SlidingTabControl);
            this.SelectionChanged += new SelectionChangedEventHandler(SlidingTabControl_SelectionChanged);
        }

        /// 
        /// Gets or sets the Tab Top Left Button style.
        /// 
        /// The left button style style.
        [Description("Gets or sets the tab top left button style")]
        [Category("ScrollButton")]
        public Style TabLeftButtonTopStyle
        {
            get { return (Style)GetValue(TabLeftButtonTopStyleProperty); }
            set { SetValue(TabLeftButtonTopStyleProperty, value); }
        }

        /// 
        /// Gets or sets the Tab Top Right Button style.
        /// 
        /// The left button style style.
        [Description("Gets or sets the tab top right button style")]
        [Category("ScrollButton")]
        public Style TabRightButtonTopStyle
        {
            get { return (Style)GetValue(TabRightButtonTopStyleProperty); }
            set { SetValue(TabRightButtonTopStyleProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            //remove old handlers
            if (null != this.tabLeftButton)
            {
                this.tabLeftButton.Click -= this.tabLeftButton_Click;
            }
            if (null != this.tabRightButton)
            {
                this.tabRightButton.Click -= this.tabRightButton_Click;
            }

            //add new handlers
            this.tabLeftButton = GetTemplateChild("TabLeftButtonTop") as RepeatButton;
            this.tabRightButton = GetTemplateChild("TabRightButtonTop") as RepeatButton;
            this.tabScrollViewer = GetTemplateChild("TabScrollViewerTop") as ScrollViewer;
            this.tabPanelTop = GetTemplateChild("TabPanelTop") as TabPanel;
            if (null != this.tabLeftButton)
            {
                this.tabLeftButton.Click += new RoutedEventHandler(tabLeftButton_Click);
            }
            if (null != this.tabRightButton)
            {
                this.tabRightButton.Click += new RoutedEventHandler(tabRightButton_Click);
            }

        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            var size = base.ArrangeOverride(finalSize);

            if (this.tabPanelTop != null && this.tabScrollViewer != null)
            {
                if (this.tabPanelTop.ActualWidth > this.tabScrollViewer.ActualWidth)
                {
                    maxHorizontalOffset = this.tabPanelTop.ActualWidth - this.tabScrollViewer.ActualWidth + 30;
                }
                SetScrollButtonVisibility();
            }

            return size;
        }
        private void SlidingTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SlidingTabControl tabControl = sender as SlidingTabControl;
            tabControl.Dispatcher.BeginInvoke(new Action(() => UpdateZIndex(sender as SlidingTabControl)));
        }
        private void tabRightButton_Click(object sender, RoutedEventArgs e)
        {
            if (null != this.tabScrollViewer && null != this.tabPanelTop)
            {
                currentHorizontalOffset = this.tabScrollViewer.HorizontalOffset + 25;
                if (currentHorizontalOffset > maxHorizontalOffset)
                    currentHorizontalOffset = maxHorizontalOffset;
                this.tabScrollViewer.ScrollToHorizontalOffset(currentHorizontalOffset);
                SetScrollButtonVisibility();
            }
        }
        private void tabLeftButton_Click(object sender, RoutedEventArgs e)
        {
            if (null != this.tabScrollViewer)
            {
                
                currentHorizontalOffset = this.tabScrollViewer.HorizontalOffset - 25;
                if (currentHorizontalOffset < 0)
                    currentHorizontalOffset = 0;
                
                this.tabScrollViewer.ScrollToHorizontalOffset(currentHorizontalOffset);
                SetScrollButtonVisibility();
            }
            
        }
        private void SetScrollButtonVisibility()
        {
            if (null != this.tabScrollViewer)
            {
                if (null != this.tabLeftButton)
                {
                    if (this.currentHorizontalOffset > 0)
                        this.tabLeftButton.Visibility = Visibility.Visible;
                    else
                        this.tabLeftButton.Visibility = Visibility.Collapsed;

                }
                if (null != this.tabRightButton)
                {
                    if (currentHorizontalOffset >= maxHorizontalOffset)
                    {
                        this.tabRightButton.Visibility = System.Windows.Visibility.Collapsed;
                    }
                    else
                    {
                        this.tabRightButton.Visibility = System.Windows.Visibility.Visible;
                    }
                }
            }
        }
        private void UpdateZIndex(SlidingTabControl tc)
        {
            if (tc != null)
            {
                foreach (TabItem tabItem in tc.Items)
                {
                    tabItem.SetValue(Canvas.ZIndexProperty, (tabItem == tc.SelectedItem ? tc.Items.Count : (tc.Items.Count - 1) - tc.Items.IndexOf(tabItem)));
                }
            }

        }

        
    }

 

file generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TabControl"
    xmlns:System_Windows_Controls_Primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls"
    >

 

    <Style TargetType="local:SlidingTabControl">
        <Setter Property="IsTabStop" Value="False"/>
        <Setter Property="Background">
            <Setter.Value>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFFFFFFF" Offset="0"/>
                    <GradientStop Color="#FFFEFEFE" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="BorderBrush">
            <Setter.Value>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFA3AEB9" Offset="0"/>
                    <GradientStop Color="#FF8399A9" Offset="0.375"/>
                    <GradientStop Color="#FF718597" Offset="0.375"/>
                    <GradientStop Color="#FF617584" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="5"/>
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        <Setter Property="VerticalContentAlignment" Value="Stretch"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:SlidingTabControl">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DisabledVisualTop">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualBottom">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualLeft">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualRight">
                                            <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Grid x:Name="TemplateTop" Visibility="Collapsed">
                         <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
       </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
       <RepeatButton Content="&lt;" x:Name="TabLeftButtonTop" Style="{TemplateBinding TabLeftButtonTopStyle}"/>
                            <ScrollViewer x:Name="TabScrollViewerTop" Grid.Column="1" IsTabStop="False" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Hidden" >
                         <System_Windows_Controls_Primitives:TabPanel x:Name="TabPanelTop" Margin="20,2,2,-1" Canvas.ZIndex="1"/>
       </ScrollViewer>
       <RepeatButton Content="&gt;" x:Name="TabRightButtonTop" Style="{TemplateBinding TabRightButtonTopStyle}" Grid.Column="2"/>
                         <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0,0,3,3" MinWidth="10" MinHeight="10" Grid.Row="1" Grid.ColumnSpan="3">
                          <ContentPresenter x:Name="ContentTop" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
                         </Border>
                         <Border x:Name="DisabledVisualTop" Background="#8CFFFFFF" CornerRadius="0,0,3,3" IsHitTestVisible="False" Opacity="0" Grid.Row="1" Grid.RowSpan="2" Canvas.ZIndex="1"/>
                        </Grid>
                        <Grid x:Name="TemplateBottom" Visibility="Collapsed">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <System_Windows_Controls_Primitives:TabPanel x:Name="TabPanelBottom" Margin="2,-1,2,2" Grid.Row="1" Canvas.ZIndex="1"/>
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3,3,0,0" MinWidth="10" MinHeight="10">
                                <ContentPresenter x:Name="ContentBottom" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
                            </Border>
                            <Border x:Name="DisabledVisualBottom" Background="#8CFFFFFF" CornerRadius="3,3,0,0" IsHitTestVisible="False" Opacity="0" Canvas.ZIndex="1"/>
                        </Grid>
                        <Grid x:Name="TemplateLeft" Visibility="Collapsed">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <System_Windows_Controls_Primitives:TabPanel x:Name="TabPanelLeft" Margin="2,2,-1,2" Canvas.ZIndex="1"/>
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" CornerRadius="0,3,3,0" MinWidth="10" MinHeight="10">
                                <ContentPresenter x:Name="ContentLeft" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
                            </Border>
                            <Border x:Name="DisabledVisualLeft" Background="#8CFFFFFF" Grid.Column="1" CornerRadius="0,3,3,0" IsHitTestVisible="False" Opacity="0" Canvas.ZIndex="1"/>
                        </Grid>
                        <Grid x:Name="TemplateRight" Visibility="Collapsed">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <System_Windows_Controls_Primitives:TabPanel x:Name="TabPanelRight" Grid.Column="1" Margin="-1,2,2,2" Canvas.ZIndex="1"/>
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3,0,0,3" MinWidth="10" MinHeight="10">
                                <ContentPresenter x:Name="ContentRight" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
                            </Border>
                            <Border x:Name="DisabledVisualRight" Background="#8CFFFFFF" CornerRadius="3,0,0,3" IsHitTestVisible="False" Margin="0" Opacity="0" Canvas.ZIndex="1"/>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

  
</ResourceDictionary>

 

Download code

SlidingTabControlDemo.zip (2.10 mb)

Tags: ,

c# | wcf ria services

set asp.net version using aspnet_regiis

I ran into a issue when trying to set a web site to use a specific .NET framework version when ASP.NET tab does not appear in IIS. (Note: this only happens on 64 bit windows 2003 server running iis in 32 bit mode).

  1. Open IIS and click on the web sites folder to get the Identifier for the web site where you want set the version of the .Net framework.
  2.  

  3. Verify the version of .Net configured for the different web sites by running aspnet_regiis –lk 
  4.  Set the framework version for the site by running aspnet_regiis –sn <PATH> where <PATH> is the path to the web site you wish to configure.
    Example: aspnet_regiis – sn w3svc/75913688/root/
    IMPORTANT:  You must run the version of aspnet_regiis associated to the version of the .Net framework you wish to register the site to use.  There is a copy of the utility in the folder for each version of the framework.

 

Tags: ,

.NET

Silverlight display special characters

I wanted to diplay an ampersand (&) in the text of a textblock.  At first I tried this

<TextBlock Text="Folders & Files"/>

 but visual studio gave me an error

If you change the code to

<TextBlock Text="Folders &amp; Files"/>


everything words fine and visual studio is happy

Other special character encodings are

Character

Encoding

&

&amp;

&quot;

<

&lt;

>

&gt;

space

&#160;

&apos;

Tags: ,

silverlight

Silverlight 4 textbox right click context menu with cut, copy and paste behavior

I wanted to be able to allow my users the ability to right click in a textbox and have a contextmenu shown to be able to cut, copy and paste. I decided to create a behavior so that the functionality can easily be added to any textbox control.


using System.Windows;

using System.Windows.Controls;

using System.Windows.Input;

using System.Windows.Interactivity;

 

namespace MyApp.Behaviors.TextBox

{

    public class TextBoxCutCopyPasteBehavior : Behavior<System.Windows.Controls.TextBox>

    {

        private ContextMenu _contextMenu;

        private MenuItem _copy;

        private MenuItem _cut;

        private MenuItem _paste;

        public TextBoxCutCopyPasteBehavior()

        {

 

            _contextMenu = new ContextMenu();

            _cut = new MenuItem();

            _cut.Header = "Cut";

            _cut.Click += new RoutedEventHandler(cut_Click);

            _contextMenu.Items.Add(_cut);

 

            _copy = new MenuItem();

            _copy.Header = "Copy";

            _copy.Click += new RoutedEventHandler(copy_Click);

            _contextMenu.Items.Add(_copy);

 

            _paste = new MenuItem();

            _paste.Header = "Paste";

            _paste.Click += new RoutedEventHandler(paste_Click);

            _contextMenu.Items.Add(_paste);

 

 

        }

 

        void paste_Click(object sender, RoutedEventArgs e)

        {

            AssociatedObject.SelectedText = Clipboard.GetText();

            _contextMenu.IsOpen = false;

        }

 

        void cut_Click(object sender, RoutedEventArgs e)

        {

            Clipboard.SetText(AssociatedObject.SelectedText);

            AssociatedObject.SelectedText = string.Empty;

            AssociatedObject.Focus();

            _contextMenu.IsOpen = false;

        }

 

        void copy_Click(object sender, RoutedEventArgs e)

        {

            Clipboard.SetText(AssociatedObject.SelectedText);

            AssociatedObject.Focus();

            _contextMenu.IsOpen = false;

        }

 

        protected override void OnAttached()

        {

 

            AssociatedObject.MouseRightButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseRightButtonDown);

            AssociatedObject.MouseRightButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseRightButtonUp);

            AssociatedObject.SetValue(ContextMenuService.ContextMenuProperty, _contextMenu);

            base.OnAttached();

        }

 

        void AssociatedObject_MouseRightButtonUp(object sender, MouseButtonEventArgs e)

        {

            if (Clipboard.ContainsText())

                _paste.IsEnabled = true;

            else

                _paste.IsEnabled = false;

 

            if (string.IsNullOrEmpty(AssociatedObject.SelectedText))

            {

                _cut.IsEnabled = false;

                _copy.IsEnabled = false;

            }

            else

            {

                _cut.IsEnabled = true;

                _copy.IsEnabled = true;

            }

            _contextMenu.IsOpen = true;

 

        }

 

        void AssociatedObject_MouseRightButtonDown(object sender, MouseButtonEventArgs e)

        {

            e.Handled = true;

        }

 

        protected override void OnDetaching()

        {

            AssociatedObject.MouseRightButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseRightButtonDown);

            AssociatedObject.MouseRightButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseRightButtonUp);

            _contextMenu = null;

            base.OnDetaching();

 

        }

 

    }

}

 

 

Once the behavior is created we can now add to our TextBox

  1. add a reference to System.Windows.Interactivity
  2. In your xaml code add
    1. xmlns

      :i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    2. xmlns

      :behaviors="clr-namespace:MyApp.Behaviors.TextBox;assembly=MyApp"
    3.  <TextBox x:Name="myTextBox" >
             <i:Interaction.Behaviors>
                 <behaviros:TextBoxCutCopyPasteBehavior/>
             </i:Interaction.Behaviors>
         </TextBox>


That's it, now you have right click support for your textbox with cut, copy and paste.

Tags: ,

behaviors | silverlight

Unable to debug Silverlight application

I was recently working on a silveright application when I suddenly noticed that my breakpoints were not being hit.  It took me a little while to figure out what was going on. 

To enable silverlight debugging make sure.

1.  <compilation debug="true" targetFramework="4.0"/>

2. Go to your .Web project file in solution explorer, right click and select Property -> click the Web tab -> at the bottom you'll see the Debuggers section, make sure ASP.NET and Silverlight are checked.

Hope this saves some of you some time.

 

Tags: ,

wcf ria services

silverlight save settings

There are lots of time when you want to be able to store user settings in between sessions of your application. I found that using Isoloated Storage makes this very easy. I created a helper class to do just this.


IsolatedStorageManager.cs

using System.IO.IsolatedStorage;

namespace MyApp.Utilities

{

    public static class IsolatedStorageManager

    {

        /// <summary>

        /// Save property and value into isolated storage

        /// </summary>

        /// <param name="value">value to store</param>

        /// <param name="name">name of property</param>

        public static void SaveIntoIsolatedStorage(object value, string name)

        {

            IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings; 

            //If settings have never been saved, then we have to add appsetting first

            if (!appSettings.Contains(name))

            {

                appSettings.Add(name, null);

            }

            //store page user is currently on for when they come back in

            appSettings[name] = value;

        }

        public static bool Contains(string name)

        {

            IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;

            return appSettings.Contains(name);

        }

        /// <summary>

        /// Remove property value from isolated storage

        /// </summary>

        /// <param name="name">name of property</param>

        public static void Remove(string name)

        {

            IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;


            //If settings have been saved, then we remove since the user wants to select a new queue/page

            if (appSettings.Contains(name))

            {

                appSettings.Remove(name);

            }

        }

        /// <summary>

        /// Removes all properties stored in isolated storage

        /// </summary>

        public static void RemoveAll()

        {

            IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;

            appSettings.Clear();

        } 

        /// <summary>

        /// Retrieve setting that was stored in Isolated Storage

        /// </summary>

        /// <param name="name">name of the property to retrieve</param>

        /// <returns></returns>

        public static object LoadFromIsolatedStorage(string name)

        {

            IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;

            if (appSettings.Contains(name))

            {

                return appSettings[name];

            }

            return null;

        }

    }

}


Now when we want to save a user setting or retrieve a user setting we can simple use our helper class.

Example: I wanted to remember the last page the user was on and automatically navigate the user to that page when they returned. Whenever a user navigated to a page I would simple store the name of the current page

IsolatedStorageManager .SaveIntoIsolatedStorage(pageName, Constants.CURRENT_PAGE);

Now when the user leaves your application and returns, we can check to see what page they were on before and return them to that page.

if (IsolatedStorageManager.Contains(Constants.CURRENT_PAGE)) //user was here before

{

   NavigateToPage((string)IsolatedStorageManager.LoadFromIsolatedStorage(Constants.CURRENT_PAGE));

 }

 else

  NavigateToPage("Home");

}

Tags: ,

c# | silverlight

Silverlight confirm dialog imported by MEF

I wanted to created a user control that would allow to me ask the user a question and then based on their answer, do something, hence I needed a confirm dialog.  I wanted to be able to use this control by adding a reference or by using MEF just to export/import my confirm dialog.  To start, I created a new silverlight application and then added a childwindow control and named it "ConfirmWindow".  Since I wanted to be able to export this control via MEF, I also created an interface for our confirm dialog.

<controls:ChildWindow x:Class="Axis.iDoc.Window.ConfirmWindow"

         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"

           Title="Confirm">

    <Grid x:Name="LayoutRoot" Width="400" Margin="2">

        <Grid.RowDefinitions>

            <RowDefinition />

            <RowDefinition Height="Auto" />

        </Grid.RowDefinitions>

 

        <TextBlock x:Name="tbMessage" TextWrapping="Wrap" Grid.Row="0" />

        <Button x:Name="CancelButton" Content="No" Click="CancelButton_Click"  Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />

        <Button x:Name="OKButton" Content="Yes" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />

    </Grid>

</controls:ChildWindow>

Code behind

[Export(PartContracts.ConfirmWindow,typeof(IConfirmWindow))]

    public partial class ConfirmWindow : ChildWindow,IConfirmWindow

    {

        public ConfirmWindow()

        {

            InitializeComponent();

            this.Closed += (s, e) => dialogResult(this.DialogResult);

        }

        Action<bool?> dialogResult;

        public void Show(string message,Action<bool?> windowClosedFunc)

        {

            if (windowClosedFunc != null)

            {

                dialogResult = windowClosedFunc;

            }

 

            tbMessage.Text = message;

            this.Show();

        }

 

        private void OKButton_Click(object sender, RoutedEventArgs e)

        {

            this.DialogResult = true;

        }

 

        private void CancelButton_Click(object sender, RoutedEventArgs e)

        {

            this.DialogResult = false;

        }

 

 

    }

 

 

You will notice that I have an Export attribute at the top because I want to be able to export my confirm window via MEF.

 

IConfirmWindow.cs

public interface IConfirmWindow

   {

       void Show(string message, Action<bool?> windowClosedFunc);

   }


 

To use this control you can either add a reference to this silverlight application or you can import it via MEF. I decided to import it via MEF.

 

private Lazy<IConfirmWindow> confirmWindow;

 

       [Import(PartContracts.ConfirmWindow, AllowDefault = true, AllowRecomposition = true)]

       public Lazy<IConfirmWindow> ConfirmWindow

       {

           get { return confirmWindow; }

           set

           {

               if (confirmWindow == value)

               {

                   return;

               }

               confirmWindow = value;

 

           }

       }

 

 I created a little helper method to show confirm window.

 

 

public void ShowConfirmWindow(string message, Action<bool?> windowClosedAction)

 

if (ConfirmWindow != null)

 

 To use the confirm dialog is the same regardless if you added a reference to it or you imported from MEF.

 

private void deleteButton_Click(object sender, RoutedEventArgs e)

{

   _window.ShowConfirmWindow("Are you sure you want to delete item?", d => confirmDelete_Closed(d));

}

void confirmDelete_Closed(bool? dialogResult)

{

    if (dialogResult.HasValue && dialogResult.Value)

    {

       //user wants to delete   

    }

}

 

{

ConfirmWindow.Value.Show(message, windowClosedAction);

}

}

 

{

 

Tags: ,

.NET | c# | silverlight

Using MEF with silverlight navigation causes error - Element is already the child of another element

I have recently been converting one of my silverlight apps to use MEF.  I had all my exports and imports defined and everything was working great until I tried to navigate to another page and then return to the page previous page, I would get the error, "element is already the child of another element".  So, the first thing I tried was clearing out my container controls that hosted my imported mef objects in the OnImportsSatisfied method.  I thought this would work since before I try to add any of my imported controls, I always clear out the control container first but this didn't work.  After doing some research and posting around, David Poll explained a little more detail on how SL navigation works.  What you will want to do is perform any clean up of your control containers in the OnNavigatedFrom event of your silvelright page.

protected override void OnNavigatedFrom(NavigationEventArgs e)
{

     //Perform any cleanup (ie clear out containers)

}

The reason this is necessary is that SL Navigation creates a new instance of the page every time you navigate to it (by default).  As a result, at no point were the imports cleared from the original container.  The next time you navigated to the URI, the same imports are being placed in new container instances (created when the new instance of the page was created).  This resulted in the same UI elements being given multiple parents, which is an error.

Tags: ,

.NET | c# | silverlight

Feedburner

I've updated my rss feed to now route through feedburner.  If you are currently subscribed to my feed, please add my new feed url

http://feeds.feedburner.com/DanSoltesz

 

Tags:

WCF Ria Services - Authentication - Add custom property and method to authenticated user

In my silverlight application I'm using wcf ria services to handle my authentication.  I wanted to add a custom property and method to my User object and have it be available to my silverlight client.

RiaContext.Current.User.MyNewProperty 

RiaContext.Current.User.MyNewMethod. 

The default silverlight business application template will create a AuthenticationService.cs file for you.

[EnableClientAccess]

public class AuthenticationService : AuthenticationBase<User>

{

}

public class User : UserBase

{     

  // NOTE: Profile properties can be added for use in Silverlight application.

  // To enable profiles, edit the appropriate section of web.config file.

 

}

First I added my property to my user class and added an attribute to exclude it from profile usage

public class User : UserBase

{

  [ProfileUsage(IsExcluded = true)]

  public IEnumerable<string> Permissions { get; private set; }

}

I didn't want this property to be saved as part of the users profile back to a database so you can set this property attribute if you don't want to setup a profile provider in your web.config. Next I tried adding my custom method to my user class but when I went to access the property in my silverlight client, the method was not showing up.  Since we are using wcf ria services, if you want methods to show up on the client then you have to explictly say so by creating a *.shared.cs class.

So to get everything working:

First you will want to move your User class out ouf the AuthenticationService.cs file and into its own User.cs file.

Next, delare your User class as a partial class.  This is so we can add our custom method via a shared file. 

Create another file called User.Shared.cs and declare this as a partial class as well along with your custom method.

Now when everything gets compiled and generated, your custom property and custom method will be available on your silverlight client user object. 

Here is what each file should look like.

AuthenticationService.cs 

[EnableClientAccess]

public class AuthenticationService : AuthenticationBase<User>

{

 

}

User.cs

public partial class User : UserBase

    {

        public User()

        {

            List<string> permissions = new List<string>();

            permissions.Add("test");

            permissions.Add("test2");

 

            Permissions = permissions; 

        }

 

        // NOTE: Profile properties can be added for use in Silverlight application.

        // To enable profiles, edit the appropriate section of web.config file.

        [ProfileUsage(IsExcluded = true)]

        public IEnumerable<string> Permissions { get; private set; }

    }

 

User.Shared.cs

public partial class User

    {

        public bool HasPermission(string permission)

        { 

            if ((this.Permissions == null))

            {

                return false;

            }

            return System.Linq.Enumerable.Contains(Permissions, permission);

        }

    }

 

Build your app and in your silverlight client you will have your new property and method

RiaContext.Current.User.Permissions

RiaContext.Current.User.HasPermissions

Tags: , , ,

.NET | c# | silverlight | wcf ria services