locked
How To Position a Ruler Above an Element On a Canvas RRS feed

  • Question

  • Hello.

    I have a ruler user control that I created.
    The ruler has values that range from negative values to positive values per inch.
    I had to do this as if the user widens the window that contains the ruler from the left, it has to display negative values on the ruler as the window is widened from the left.

    I have a canvas that contains children that are added dynamically when the user elects to add an object to the canvas. Each object that's added to the canvas needs to have the ruler placed above it.
    The issue that I'm having is that the 0 inch marker on the ruler needs to match up with the top left border of the object that's placed on the canvas.

    So if my ruler goes from say -3        -2        -1        0        1        2        3, the 0 part of the ruler will be aligned top left of the object that it sits above.

    Here's the xaml code where the ruler is added to the canvas.
                    <Canvas Name="DesignCanvas"   
                            Margin="5"   
                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > 
                        <local:Ruler x:Name="RulerX"                             
                               VerticalAlignment="Top"   
                               Height="50">       
                        </local:Ruler>        
                    </Canvas> 

    Here's the VB code where the object and the ruler (RulerX) are added to the canvas.
            Dim compositionBackground As New Rectangle  
            With compositionBackground  
                .Width = _design.LabelStock.LabelComposition.Width * 96  
                .Height = _design.LabelStock.LabelComposition.Height * 96  
     
                .Fill = New SolidColorBrush(Colors.White)  
                .StrokeThickness = 0 
                .Opacity = 0.75  
                Me.Width = .Width  
                Me.Height = .Height  
                Me.BackgroundCanvas.Width = .Width * 3  
                Me.BackgroundCanvas.Height = .Height * 3  
                Me.DesignCanvas.Width = .Width  
                Me.DesignCanvas.Height = .Height  
     
                Dim horizontalOffset As Double = Me.BackgroundCanvas.Width * 0.5 - .Width * 0.5  
                Dim verticalOffset As Double = Me.BackgroundCanvas.Height * 0.5 - .Height * 0.5  
     
                Canvas.SetLeft(compositionBackground, horizontalOffset)  
                Canvas.SetTop(compositionBackground, verticalOffset)  
                Canvas.SetLeft(Me.DesignCanvas, horizontalOffset)  
                Canvas.SetTop(Me.DesignCanvas, verticalOffset)  
     
                Canvas.SetLeft(RulerX, horizontalOffset - RulerX.Width * 0.5)  
            End With  
     
            With Me.BackgroundCanvas  
                .Children.Add(compositionBackground)  
            End With 

    With this code the RulerX is placed over the top of the object and a negative value from the rule is positioned on the left, not 0.

    Thanks,
    Rita
    Wednesday, March 11, 2009 9:58 PM

Answers


  • It take 3 steps to upload a picture or video:


    1 Convert the video file into GIF format.

    2 Upload the gif image to a server(I use picasa ).

    3 Embed the image into the content of your thread

    • Marked as answer by Tao Liang Thursday, March 19, 2009 2:02 AM
    Thursday, March 19, 2009 2:01 AM
  • You should calculate the Position of element that be added into Canvas.
    And set the Top and Left of Ruler to make the Ruler to anchor the element.
    Below is a simple that show how to anchor a Ruler to a Rectangle.

    It just like this:

    Hope it helps.
    XAML:
    <Window x:Class="WPFRuler.Window1" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            xmlns:loacl="clr-namespace:WPFRuler" 
        Title="Window1" Height="600" Width="600"
        <StackPanel> 
            <Button Width="150" Click="Button_Click">Add Element</Button> 
            <Canvas Background="Azure" Name="DesignCanvas"    
                         Width="500" 
                    Height="500" 
                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > 
            </Canvas> 
        </StackPanel> 
    </Window> 
     

    • Proposed as answer by Tao Liang Wednesday, March 18, 2009 8:35 AM
    • Marked as answer by Tao Liang Thursday, March 19, 2009 2:02 AM
    Wednesday, March 18, 2009 8:27 AM
  • Here's my answer to the question regarding allowing for different screen widths with the ruler (with markings from negative values through positive values)
    so that the ruler correctly positions itself above an element at marking 0 (and not the left most negative marking) .

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dcfec4f3-ec4b-4bf3-aa39-be3e6f510064

     
    • Marked as answer by ritagreen Thursday, March 19, 2009 6:28 PM
    Thursday, March 19, 2009 6:25 PM

All replies

  • For more detailed information, can you paste your full version code here?
    You can use the brush like icon on the top-right of the editor.
    Then I can compile your program and try to add the function or feature you have asked.

    Wednesday, March 18, 2009 6:59 AM
  • You should calculate the Position of element that be added into Canvas.
    And set the Top and Left of Ruler to make the Ruler to anchor the element.
    Below is a simple that show how to anchor a Ruler to a Rectangle.

    It just like this:

    Hope it helps.
    XAML:
    <Window x:Class="WPFRuler.Window1" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            xmlns:loacl="clr-namespace:WPFRuler" 
        Title="Window1" Height="600" Width="600"
        <StackPanel> 
            <Button Width="150" Click="Button_Click">Add Element</Button> 
            <Canvas Background="Azure" Name="DesignCanvas"    
                         Width="500" 
                    Height="500" 
                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > 
            </Canvas> 
        </StackPanel> 
    </Window> 
     

    • Proposed as answer by Tao Liang Wednesday, March 18, 2009 8:35 AM
    • Marked as answer by Tao Liang Thursday, March 19, 2009 2:02 AM
    Wednesday, March 18, 2009 8:27 AM
  • C#:
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using System.Globalization;
    using System.Collections;
    using System.Deployment.Application;
    using System.IO.IsolatedStorage;
    using System.Xml.Serialization;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Xml;
    namespace WPFRuler
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
            }
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                //Create a Rectangle
                Rectangle element = new Rectangle();
                element.Width = 100;
                element.Height = 50;
                Canvas.SetTop(element, 200);
                Canvas.SetLeft(element, 150);
                element.Fill = Brushes.Red;
                //Add the Rectangle into the Canvas
                DesignCanvas.Children.Add(element);
                //Locate a Ruler and anchor it to the Rectangle
                Ruler r = new Ruler();
                Canvas.SetTop(r, 200 - r.Height);
                Canvas.SetLeft(r, 150);
                DesignCanvas.Children.Add(r);
            }
        }
        #region
        public class Ruler : FrameworkElement
        {
            static Ruler()
            {
                HeightProperty.OverrideMetadata(
                    typeof(Ruler),
                    new FrameworkPropertyMetadata(40.0));
            }
            /// <summary>
            /// Gets or sets the length of the ruler.
            /// Default value is 10.0.
            /// </summary>
            public double Length
            {
                get { return (double)GetValue(LengthProperty); }
                set { SetValue(LengthProperty, value); }
            }
            /// <summary>
            /// Identifies the Length dependency property.
            /// </summary>
            public static readonly DependencyProperty LengthProperty =
                DependencyProperty.Register(
                    "Length",
                    typeof(double),
                    typeof(Ruler),
                    new UIPropertyMetadata(10.0));
            /// <summary>
            /// Gets or sets the unit of the ruler.
            /// Default value is Unit.Cm.
            /// </summary>
            public Unit Unit
            {
                get { return (Unit)GetValue(UnitProperty); }
                set { SetValue(UnitProperty, value); }
            }
            /// <summary>
            /// Identifies the Unit dependency property.
            /// </summary>
            public static readonly DependencyProperty UnitProperty =
                DependencyProperty.Register(
                    "Unit",
                    typeof(Unit),
                    typeof(Ruler),
                    new UIPropertyMetadata(Unit.Cm));
            private const double _segmentHeight = 20.0;
            private Pen _p = new Pen(Brushes.Black, 1.0);
            private Pen _pThin = new Pen(Brushes.Black, 0.5);
            private Pen _pBorder = new Pen(Brushes.Gray, 1.0);
            /// <summary>
            /// Participates in rendering operations.
            /// </summary>
            /// <param name="drawingContext">The drawing instructions for a specific element. This context is provided to the layout system.</param>
            protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
            {
                base.OnRender(drawingContext);
                double xDest;
                if (Unit == Unit.Cm)
                {
                    xDest = DipHelper.CmToDip(Length);
                }
                else
                {
                    xDest = DipHelper.InchToDip(Length);
                }
                drawingContext.DrawRectangle(null, _pBorder, new Rect(new Point(0.0, 0.0), new Point(xDest, this.Height)));
                for (double dUnit = 0.0; dUnit <= Length; dUnit++)
                {
                    double d;
                    if (Unit == Unit.Cm)
                    {
                        d = DipHelper.CmToDip(dUnit);
                        if (dUnit < Length)
                        {
                            for (int i = 1; i <= 9; i++)
                            {
                                if (i != 5)
                                {
                                    double dMm = DipHelper.CmToDip(dUnit + 0.1 * i);
                                    drawingContext.DrawLine(_pThin, new Point(dMm, this.Height), new Point(dMm, this.Height - _segmentHeight / 3.0));
                                }
                            }
                            double dMiddle = DipHelper.CmToDip(dUnit + 0.5);
                            drawingContext.DrawLine(_p, new Point(dMiddle, this.Height), new Point(dMiddle, this.Height - _segmentHeight * 2.0 / 3.0));
                        }
                    }
                    else
                    {
                        d = DipHelper.InchToDip(dUnit);
                        if (dUnit < Length)
                        {
                            double dQuarter = DipHelper.InchToDip(dUnit + 0.25);
                            drawingContext.DrawLine(_pThin, new Point(dQuarter, this.Height), new Point(dQuarter, this.Height - _segmentHeight / 3.0));
                            double dMiddle = DipHelper.InchToDip(dUnit + 0.5);
                            drawingContext.DrawLine(_p, new Point(dMiddle, this.Height), new Point(dMiddle, this.Height - 0.5 * _segmentHeight * 2.0 / 3.0));
                            double d3Quarter = DipHelper.InchToDip(dUnit + 0.75);
                            drawingContext.DrawLine(_pThin, new Point(d3Quarter, this.Height), new Point(d3Quarter, this.Height - 0.25 * _segmentHeight / 3.0));
                        }
                    }
                    drawingContext.DrawLine(_p, new Point(d, this.Height), new Point(d, this.Height - _segmentHeight));
                    if ((dUnit != 0.0) && (dUnit < Length))
                    {
                        FormattedText ft = new FormattedText(
                            dUnit.ToString(CultureInfo.CurrentCulture),
                            CultureInfo.CurrentCulture,
                            FlowDirection.LeftToRight,
                            new Typeface("Arial"),
                            DipHelper.PtToDip(10.0),
                            Brushes.Black);
                        ft.SetFontWeight(FontWeights.Regular);
                        ft.TextAlignment = TextAlignment.Center;
                        drawingContext.DrawText(ft, new Point(d, this.Height - _segmentHeight - ft.Height));
                    }
                }
            }
            /// <summary>
            /// Measures an instance during the first layout pass prior to arranging it.
            /// </summary>
            /// <param name="availableSize">A maximum Size to not exceed.</param>
            /// <returns>The maximum Size for the instance.</returns>
            protected override Size MeasureOverride(Size availableSize)
            {
                Size desiredSize;
                if (Unit == Unit.Cm)
                {
                    desiredSize = new Size(DipHelper.CmToDip(Length), this.Height);
                }
                else
                {
                    desiredSize = new Size(DipHelper.InchToDip(Length), this.Height);
                }
                return desiredSize;
            }
        }
        #endregion
        #region
        public enum Unit
        {
            /// <summary>
            /// the unit is Centimeter.
            /// </summary>
            Cm,
            /// <summary>
            /// The unit is Inch.
            /// </summary>
            Inch
        };
        public static class DipHelper
        {
            /// <summary>
            /// Static constructor.
            /// </summary>
            static DipHelper()
            {
                if (AssemblyConfigManager.Settings[_screenSizeKey] == null)
                {
                    AssemblyConfigManager.Settings[_screenSizeKey] = 17.0;
                }
                if (AssemblyConfigManager.Settings[_screenIndependentScaleXKey] == null)
                {
                    AssemblyConfigManager.Settings[_screenIndependentScaleXKey] = 1.0;
                }
                else
                {
                    ScreenIndependentScaleTransform.ScaleX = (double)AssemblyConfigManager.Settings[_screenIndependentScaleXKey];
                }
                if (AssemblyConfigManager.Settings[_screenIndependentScaleYKey] == null)
                {
                    AssemblyConfigManager.Settings[_screenIndependentScaleYKey] = 1.0;
                }
                else
                {
                    ScreenIndependentScaleTransform.ScaleY = (double)AssemblyConfigManager.Settings[_screenIndependentScaleYKey];
                }
                if (AssemblyConfigManager.Settings[_screenSizeKey] == null)
                {
                    AssemblyConfigManager.Settings[_screenSizeKey] = 17.0;
                }
            }
            /// <summary>
            /// Converts millimeters to DIP (Device Independant Pixels).
            /// </summary>
            /// <param name="mm">A millimeter value.</param>
            /// <returns>A DIP value.</returns>
            public static double MmToDip(double mm)
            {
                return CmToDip(mm / 10.0);
            }
            /// <summary>
            /// Converts centimeters to DIP (Device Independant Pixels).
            /// </summary>
            /// <param name="cm">A centimeter value.</param>
            /// <returns>A DIP value.</returns>
            public static double CmToDip(double cm)
            {
                return (cm * 96.0 / 2.54);
            }
            /// <summary>
            /// Converts inches to DIP (Device Independant Pixels).
            /// </summary>
            /// <param name="inch">An inch value.</param>
            /// <returns>A DIP value.</returns>
            public static double InchToDip(double inch)
            {
                return (inch * 96.0);
            }
            /// <summary>
            /// Converts font points to DIP (Device Independant Pixels).
            /// </summary>
            /// <param name="pt">A font point value.</param>
            /// <returns>A DIP value.</returns>
            public static double PtToDip(double pt)
            {
                return (pt * 96.0 / 72.0);
            }
            /// <summary>
            /// Converts DIP (Device Independant Pixels) to centimeters.
            /// </summary>
            /// <param name="dip">A DIP value.</param>
            /// <returns>A centimeter value.</returns>
            public static double DipToCm(double dip)
            {
                return (dip * 2.54 / 96.0);
            }
            /// <summary>
            /// Converts DIP (Device Independant Pixels) to millimeters.
            /// </summary>
            /// <param name="dip">A DIP value.</param>
            /// <returns>A millimeter value.</returns>
            public static double DipToMm(double dip)
            {
                return DipToCm(dip) * 10.0;
            }
            /// <summary>
            /// Gets the system DPI scale factor (compared to 96 dpi).
            /// From http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx
            /// Should not be called before the Loaded event (else XamlException mat throw)
            /// </summary>
            /// <returns>A Point object containing the X- and Y- scale factor.</returns>
            private static Point GetSystemDpiFactor()
            {
                PresentationSource source = PresentationSource.FromVisual(Application.Current.MainWindow);
                Matrix m = source.CompositionTarget.TransformToDevice;
                return new Point(m.M11, m.M22);
            }
            private const double _dpiBase = 96.0;
            /// <summary>
            /// Gets the system configured DPI.
            /// </summary>
            /// <returns>A Point object containing the X- and Y- DPI.</returns>
            public static Point GetSystemDpi()
            {
                Point sysDpiFactor = GetSystemDpiFactor();
                return new Point(
                    sysDpiFactor.X * _dpiBase,
                    sysDpiFactor.Y * _dpiBase);
            }
            /// <summary>
            /// Gets the physical pixel density (DPI) of the screen.
            /// </summary>
            /// <param name="diagonalScreenSize">Size - in inch - of the diagonal of the screen.</param>
            /// <returns>A Point object containing the X- and Y- DPI.</returns>
            public static Point GetPhysicalDpi(double diagonalScreenSize)
            {
                Point sysDpiFactor = GetSystemDpiFactor();
                double pixelScreenWidth = SystemParameters.PrimaryScreenWidth * sysDpiFactor.X;
                double pixelScreenHeight = SystemParameters.PrimaryScreenHeight * sysDpiFactor.Y;
                double formatRate = pixelScreenWidth / pixelScreenHeight;
                double inchHeight = diagonalScreenSize / Math.Sqrt(formatRate * formatRate + 1.0);
                double inchWidth = formatRate * inchHeight;
                double xDpi = Math.Round(pixelScreenWidth / inchWidth);
                double yDpi = Math.Round(pixelScreenHeight / inchHeight);
                return new Point(xDpi, yDpi);
            }
            /// <summary>
            /// Converts a DPI into a scale factor (compared to system DPI).
            /// </summary>
            /// <param name="dpi">A Point object containing the X- and Y- DPI to convert.</param>
            /// <returns>A Point object containing the X- and Y- scale factor.</returns>
            public static Point DpiToScaleFactor(Point dpi)
            {
                Point sysDpi = GetSystemDpi();
                return new Point(
                    dpi.X / sysDpi.X,
                    dpi.Y / sysDpi.Y);
            }
            /// <summary>
            /// Gets the scale factor to apply to a WPF application
            /// so that 96 DIP always equals 1 inch on the screen (whatever the system DPI).
            /// </summary>
            /// <param name="diagonalScreenSize">Size - in inch - of the diagonal of the screen</param>
            /// <returns>A Point object containing the X- and Y- scale factor.</returns>
            public static Point GetScreenIndependentScaleFactor(double diagonalScreenSize)
            {
                return DpiToScaleFactor(GetPhysicalDpi(diagonalScreenSize));
            }
            private static string _screenIndependentScaleXKey = "ScreenIndependentScaleX";
            private static string _screenIndependentScaleYKey = "ScreenIndependentScaleY";
            private static string _screenSizeKey = "ScreenSize";
            /// <summary>
            /// Gets or sets the screen independent X scale factor.
            /// It must be initialized to a real value.
            /// </summary>
            public static double ScreenIndependentScaleX
            {
                get { return (double)AssemblyConfigManager.Settings[_screenIndependentScaleXKey]; }
                set
                {
                    _screenIndependentScaleTransform.ScaleX = value;
                    AssemblyConfigManager.Settings[_screenIndependentScaleXKey] = value;
                }
            }
            /// <summary>
            /// Gets or sets the screen independent Y scale factor.
            /// It must be initialized to a real value.
            /// </summary>
            public static double ScreenIndependentScaleY
            {
                get { return (double)AssemblyConfigManager.Settings[_screenIndependentScaleYKey]; }
                set
                {
                    _screenIndependentScaleTransform.ScaleY = value;
                    AssemblyConfigManager.Settings[_screenIndependentScaleYKey] = value;
                }
            }
            private static ScaleTransform _screenIndependentScaleTransform = new ScaleTransform();
            /// <summary>
            /// Gets the screen independent scale transform object.
            /// It must be initialized to a real scale factor.
            /// </summary>
            public static ScaleTransform ScreenIndependentScaleTransform
            {
                get { return DipHelper._screenIndependentScaleTransform; }
            }
            /// <summary>
            /// Gets or sets the machine diagonal screen size.
            /// It must be initialized to a real value.
            /// </summary>
            public static double ScreenSize
            {
                get { return (double)AssemblyConfigManager.Settings[_screenSizeKey]; }
                set { AssemblyConfigManager.Settings[_screenSizeKey] = value; }
            }
        }
        public static class AssemblyConfigManager
        {
            private static string _perspectiveFilename = "Perspective.Core.dat";
            /// <summary>
            /// Static constructor. Loads the Settings dictionary from isolated storage.
            /// </summary>
            static AssemblyConfigManager()
            {
                LoadSettings();
            }
            private static Hashtable _settings = new Hashtable();
            /// <summary>
            /// Gets a dictionary containing the Perspective.Core assembly settings.
            /// </summary>
            public static Hashtable Settings
            {
                get { return _settings; }
            }
            /// <summary>
            /// Fills the Settings dictionary with the values stored in an isolated storage corresponding to the Perspective.Core assembly.
            /// </summary>
            public static void LoadSettings()
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    IsolatedStorageHelper.LoadFromUserStoreForApplication(
                        _settings,
                        _perspectiveFilename);
                }
                else
                {
                    IsolatedStorageHelper.LoadForDomain(_settings,
                        IsolatedStorageScope.Assembly |
                        IsolatedStorageScope.Machine,
                        _perspectiveFilename);
                }
            }
            /// <summary>
            /// Saves the Settings dictionary in an isolated storage corresponding to the Perspective.Core assembly.
            /// </summary>
            public static void SaveSettings()
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    IsolatedStorageHelper.SaveToUserStoreForApplication(
                        _settings,
                        _perspectiveFilename);
                }
                else
                {
                    IsolatedStorageHelper.SaveForDomain(_settings,
                        IsolatedStorageScope.Assembly |
                        IsolatedStorageScope.Machine,
                        _perspectiveFilename);
                }
            }
        }
        public static class IsolatedStorageHelper
        {
            /// <summary>
            /// Fills a dictionary with the values stored in an isolated storage corresponding to the kind of application (installed or ClickOnce deployed).
            /// </summary>
            /// <param name="dictionary">The dictionary to fill.</param>
            /// <param name="fileName">The file name.</param>
            public static void Load(IDictionary dictionary, string fileName)
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    IsolatedStorageHelper.LoadFromUserStoreForApplication(
                        dictionary,
                        fileName);
                }
                else
                {
                    IsolatedStorageHelper.LoadFromUserStoreForDomain(
                        dictionary,
                        fileName);
                }
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an isolated storage corresponding to the kind of application (installed or ClickOnce deployed).
            /// </summary>
            /// <param name="sd">The dictionary to fill.</param>
            /// <param name="fileName">The file name.</param>
            public static void Load(StorableDictionary sd, string fileName)
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    IsolatedStorageHelper.LoadFromUserStoreForApplication(
                        sd,
                        fileName);
                }
                else
                {
                    IsolatedStorageHelper.LoadFromUserStoreForDomain(
                        sd,
                        fileName);
                }
            }
            /// <summary>
            /// Save a dictionary into an isolated storage corresponding to the kind of application (installed or ClickOnce deployed).
            /// This method is not compatible with partial-trust in a ClickOnce application.
            /// </summary>
            /// <param name="dictionary">The dictionary to save.</param>
            /// <param name="fileName">The file name.</param>
            public static void Save(IDictionary dictionary, string fileName)
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    IsolatedStorageHelper.SaveToUserStoreForApplication(
                        dictionary,
                        fileName);
                }
                else
                {
                    IsolatedStorageHelper.SaveToUserStoreForDomain(
                        dictionary,
                        fileName);
                }
            }
            /// <summary>
            /// Save a dictionary into an isolated storage corresponding to the kind of application (installed or ClickOnce deployed).
            /// </summary>
            /// <param name="sd">The dictionary to save.</param>
            /// <param name="fileName">The file name.</param>
            public static void Save(StorableDictionary sd, string fileName)
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    IsolatedStorageHelper.SaveToUserStoreForApplication(
                        sd,
                        fileName);
                }
                else
                {
                    IsolatedStorageHelper.SaveToUserStoreForDomain(
                        sd,
                        fileName);
                }
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an user-scoped isolated storage corresponding to the calling code's application identity.
            /// This requires a ClickOnce aplication (see http://blogs.msdn.com/shawnfa/archive/2006/01/18/514407.aspx).
            /// First, the dictionary is emptied.
            /// </summary>
            /// <param name="dictionary">The dictionary to fill.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadFromUserStoreForApplication(IDictionary dictionary, string fileName)
            {
                LoadForApplication(dictionary,
                    IsolatedStorageScope.Application |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an user-scoped isolated storage corresponding to the calling code's application identity.
            /// This requires a ClickOnce aplication (see http://blogs.msdn.com/shawnfa/archive/2006/01/18/514407.aspx).
            /// First, the dictionary is emptied.
            /// </summary>
            /// <param name="sd">The dictionary to fill.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadFromUserStoreForApplication(StorableDictionary sd, string fileName)
            {
                LoadForApplication(sd,
                    IsolatedStorageScope.Application |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Saves a dictionary in an user-scoped isolated storage corresponding to the calling code's application identity.
            /// This requires a ClickOnce aplication (see http://blogs.msdn.com/shawnfa/archive/2006/01/18/514407.aspx).
            /// This method is not compatible with partial-trust in a ClickOnce application.
            /// </summary>
            /// <param name="dictionary">The dictionary to save.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveToUserStoreForApplication(IDictionary dictionary, string fileName)
            {
                SaveForApplication(dictionary,
                    IsolatedStorageScope.Application |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Saves a dictionary in an user-scoped isolated storage corresponding to the calling code's application identity.
            /// This requires a ClickOnce aplication (see http://blogs.msdn.com/shawnfa/archive/2006/01/18/514407.aspx).
            /// </summary>
            /// <param name="sd">The dictionary to save.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveToUserStoreForApplication(StorableDictionary sd, string fileName)
            {
                SaveForApplication(sd,
                    IsolatedStorageScope.Application |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Deletes a file in an user-scoped isolated storage corresponding to the calling code's application identity.
            /// This requires a ClickOnce aplication (see http://blogs.msdn.com/shawnfa/archive/2006/01/18/514407.aspx).
            /// </summary>
            /// <param name="fileName">The relative path of the file to delete within the isolated storage scope.</param>
            public static void DeleteFileFromUserStoreForApplication(string fileName)
            {
                DeleteFileForApplication(
                    IsolatedStorageScope.Application |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Deletes a directory in an user-scoped isolated storage corresponding to the calling code's application identity.
            /// This requires a ClickOnce aplication (see http://blogs.msdn.com/shawnfa/archive/2006/01/18/514407.aspx).
            /// </summary>
            /// <param name="dir">The relative path of the directory to delete within the isolated storage scope.</param>
            public static void DeleteDirectoryFromUserStoreForApplication(string dir)
            {
                DeleteFileForApplication(
                    IsolatedStorageScope.Application |
                    IsolatedStorageScope.User,
                    dir);
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an user-scoped isolated storage corresponding to the application domain identity and Perspective.Core assembly identity.
            /// First, the dictionary is emptied.
            /// </summary>
            /// <param name="dictionary">The dictionary to fill.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadFromUserStoreForDomain(IDictionary dictionary, string fileName)
            {
                LoadForDomain(dictionary,
                    IsolatedStorageScope.Assembly |
                    IsolatedStorageScope.Domain |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an user-scoped isolated storage corresponding to the application domain identity and Perspective.Core assembly identity.
            /// First, the dictionary is emptied.
            /// </summary>
            /// <param name="sd">The dictionary to fill.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadFromUserStoreForDomain(StorableDictionary sd, string fileName)
            {
                LoadForDomain(sd,
                    IsolatedStorageScope.Assembly |
                    IsolatedStorageScope.Domain |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Saves a dictionary in an user-scoped isolated storage corresponding to the application domain identity and Perspective.Core assembly identity.
            /// This method is not compatible with partial-trust.
            /// </summary>
            /// <param name="dictionary">The dictionary to save.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveToUserStoreForDomain(IDictionary dictionary, string fileName)
            {
                SaveForDomain(dictionary,
                    IsolatedStorageScope.Assembly |
                    IsolatedStorageScope.Domain |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Saves a dictionary in an user-scoped isolated storage corresponding to the application domain identity and Perspective.Core assembly identity.
            /// </summary>
            /// <param name="sd">The dictionary to save.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveToUserStoreForDomain(StorableDictionary sd, string fileName)
            {
                SaveForDomain(sd,
                    IsolatedStorageScope.Assembly |
                    IsolatedStorageScope.Domain |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Deletes a file in an user-scoped isolated storage corresponding to the application domain identity and Perspective.Core assembly identity.
            /// </summary>
            /// <param name="fileName">The relative path of the file to delete within the isolated storage scope.</param>
            public static void DeleteFileFromUserStoreForDomain(string fileName)
            {
                DeleteDirectoryForDomain(
                    IsolatedStorageScope.Assembly |
                    IsolatedStorageScope.Domain |
                    IsolatedStorageScope.User,
                    fileName);
            }
            /// <summary>
            /// Deletes a directory in an user-scoped isolated storage corresponding to the application domain identity and Perspective.Core assembly identity.
            /// </summary>
            /// <param name="dir">The relative path of the directory to delete within the isolated storage scope.</param>
            public static void DeleteDirectoryFromUserStoreForDomain(string dir)
            {
                DeleteDirectoryForDomain(
                    IsolatedStorageScope.Assembly |
                    IsolatedStorageScope.Domain |
                    IsolatedStorageScope.User,
                    dir);
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an isolated store,
            /// for application domain and assembly.
            /// </summary>
            /// <param name="dictionary">The dictionary to fill.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadForDomain(IDictionary dictionary, IsolatedStorageScope scope, string fileName)
            {
                using (IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null, null))
                {
                    LoadFromStorageFile(storage, dictionary, fileName);
                }
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an isolated store,
            /// for application domain and assembly.
            /// </summary>
            /// <param name="sd">The dictionary to fill.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadForDomain(StorableDictionary sd, IsolatedStorageScope scope, string fileName)
            {
                using (IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null, null))
                {
                    LoadFromStorageFile(storage, sd, fileName);
                }
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an isolated store,
            /// for application.
            /// </summary>
            /// <param name="dictionary">The dictionary to fill.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadForApplication(IDictionary dictionary, IsolatedStorageScope scope, string fileName)
            {
                using (IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null))
                {
                    LoadFromStorageFile(storage, dictionary, fileName);
                }
            }
            /// <summary>
            /// Fills a dictionary with the values stored in an isolated store,
            /// for application.
            /// </summary>
            /// <param name="sd">The dictionary to fill.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void LoadForApplication(StorableDictionary sd, IsolatedStorageScope scope, string fileName)
            {
                using (IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null))
                {
                    LoadFromStorageFile(storage, sd, fileName);
                }
            }
            private static void LoadFromStorageFile(
                IsolatedStorageFile storage,
                IDictionary dictionary,
                string fileName)
            {
                string[] files = storage.GetFileNames(fileName);
                if ((files.Length > 0) && (files[0] == fileName))
                {
                    using (Stream stream =
                        new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
                    {
                        if (stream.Length > 0)
                        {
                            IFormatter formatter = new BinaryFormatter();
                            IDictionary data = (IDictionary)formatter.Deserialize(stream);
                            IDictionaryEnumerator enumerator = data.GetEnumerator();
                            while (enumerator.MoveNext())
                            {
                                dictionary.Add(enumerator.Key, enumerator.Value);
                            }
                        }
                    }
                }
            }
            private static void LoadFromStorageFile(
                IsolatedStorageFile storage,
                StorableDictionary sd,
                string fileName)
            {
                string[] files = storage.GetFileNames(fileName);
                if ((files.Length > 0) && (files[0] == fileName))
                {
                    using (Stream stream =
                        new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
                    {
                        if (stream.Length > 0)
                        {
                            XmlSerializer xs = new XmlSerializer(typeof(StorableDictionary));
                            StorableDictionary sd2 = (StorableDictionary)xs.Deserialize(stream); //, sd);
                            foreach (KeyValuePair<string, object> kvp in sd2)
                            {
                                sd.Add(kvp.Key, kvp.Value);
                            }
                        }
                    }
                }
            }
            /// <summary>
            /// Saves a dictionary in an isolated store.
            /// for application domain and assembly.
            /// This method is not compatible with partial-trust.
            /// </summary>
            /// <param name="dictionary">The dictionary to save.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveForDomain(IDictionary dictionary, IsolatedStorageScope scope, string fileName)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null, null);
                SaveToStorageFile(storage, dictionary, fileName);
            }
            /// <summary>
            /// Saves a dictionary in an isolated store.
            /// for application domain and assembly.
            /// </summary>
            /// <param name="sd">The dictionary to save.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveForDomain(StorableDictionary sd, IsolatedStorageScope scope, string fileName)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null, null);
                SaveToStorageFile(storage, sd, fileName);
            }
            /// <summary>
            /// Saves a dictionary in an isolated store
            /// for application.
            /// This method is not compatible with partial-trust.
            /// </summary>
            /// <param name="dictionary">The dictionary to save.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveForApplication(IDictionary dictionary, IsolatedStorageScope scope, string fileName)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null);
                SaveToStorageFile(storage, dictionary, fileName);
            }
            /// <summary>
            /// Saves a dictionary in an isolated store
            /// for application.
            /// </summary>
            /// <param name="sd">The dictionary to save.</param>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The file name.</param>
            public static void SaveForApplication(StorableDictionary sd, IsolatedStorageScope scope, string fileName)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null);
                SaveToStorageFile(storage, sd, fileName);
            }
            // Binary serialization is not compatible with partial-trust
            private static void SaveToStorageFile(
                IsolatedStorageFile storage,
                IDictionary dictionary,
                string fileName)
            {
                using (IsolatedStorageFileStream stream =
                    new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
                {
                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, dictionary);
                }
            }
            private static void SaveToStorageFile(
                IsolatedStorageFile storage,
                StorableDictionary sd,
                string fileName)
            {
                using (IsolatedStorageFileStream stream =
                    new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
                {
                    XmlSerializer xs = new XmlSerializer(typeof(StorableDictionary));
                    xs.Serialize(stream, sd);
                }
            }
            /// <summary>
            /// Deletes a file in the isolated storage scope
            /// for application domain and assembly.
            /// </summary>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The relative path of the file to delete within the isolated storage scope.</param>
            public static void DeleteFileForDomain(IsolatedStorageScope scope, string fileName)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null, null);
                storage.DeleteFile(fileName);
            }
            /// <summary>
            /// Deletes a directory in the isolated storage scope
            /// for application domain and assembly.
            /// </summary>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="dir">The relative path of the directory to delete within the isolated storage scope.</param>
            public static void DeleteDirectoryForDomain(IsolatedStorageScope scope, string dir)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null, null);
                storage.DeleteDirectory(dir);
            }
            /// <summary>
            /// Deletes a file in the isolated storage scope
            /// for application.
            /// </summary>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="fileName">The relative path of the file to delete within the isolated storage scope.</param>
            public static void DeleteFileForApplication(IsolatedStorageScope scope, string fileName)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null);
                storage.DeleteFile(fileName);
            }
            /// <summary>
            /// Deletes a directory in the isolated storage scope
            /// for application.
            /// </summary>
            /// <param name="scope">The degree of scope for the isolated store : a bitwise combination of the IsolatedStorageScope values.</param>
            /// <param name="dir">The relative path of the directory to delete within the isolated storage scope.</param>
            public static void DeleteDirectoryForApplication(IsolatedStorageScope scope, string dir)
            {
                IsolatedStorageFile storage = IsolatedStorageFile.GetStore(scope, null);
                storage.DeleteDirectory(dir);
            }
        }
        [Serializable()]
        public class StorableDictionary : Dictionary<string, object>, IXmlSerializable
        {
            private const string _rootElementName = "StorableDictionary";
            private const string _entryElementName = "Entry";
            private const string _keyAttributeName = "Key";
            #region IXmlSerializable Members
            /// <summary>
            /// Implements IXmlSerializable.GetSchema()
            /// </summary>
            /// <returns></returns>
            public System.Xml.Schema.XmlSchema GetSchema()
            {
                return null;
            }
            /// <summary>
            /// Generates an object from its XML representation.
            /// </summary>
            /// <param name="reader">The XmlReader stream from which the object is deserialized.</param>
            public void ReadXml(System.Xml.XmlReader reader)
            {
                this.Clear();
                XmlSerializer xs = new XmlSerializer(typeof(object));

                reader.ReadStartElement(_rootElementName);
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    string value = reader.GetAttribute(_keyAttributeName);
                    reader.ReadStartElement(_entryElementName);
                    string xml = reader.ReadOuterXml();
                    if (!String.IsNullOrEmpty(value))
                    {
                        StringReader sr = new StringReader(xml);
                        XmlTextReader xr = new XmlTextReader(sr);
                        object o = xs.Deserialize(xr);
                        this.Add(value, o);
                    }
                    reader.ReadEndElement();
                }

                reader.ReadEndElement();
            }
            /// <summary>
            /// Converts an object into its XML representation.
            /// </summary>
            /// <param name="writer">The XmlWriter stream to which the object is serialized.</param>
            public void WriteXml(System.Xml.XmlWriter writer)
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
                XmlSerializer xs = new XmlSerializer(typeof(object));
                foreach (KeyValuePair<string, object> kvp in this)
                {
                    writer.WriteStartElement(_entryElementName);
                    writer.WriteAttributeString(_keyAttributeName, kvp.Key);
                    xs.Serialize(writer, kvp.Value, ns);
                    writer.WriteEndElement();
                }
            }
            #endregion
        }
        #endregion
    }

    • Proposed as answer by Tao Liang Wednesday, March 18, 2009 8:36 AM
    Wednesday, March 18, 2009 8:29 AM
  • Wow! Thanks so much for your response.
    I'll be spending the next few hours working through the code (I'm a VB'r!) and will post an update later on. 
    Wednesday, March 18, 2009 3:19 PM
  • Well, after spending quite some time on this I made some ground and got it working but still have one problem - different screen widths!
    I can position my horizontal and vertical rulers correctly above an element with the center of the rulers (0) positioned at the top left of the element.

    The problem is that when it's run on a screen with a different width the ruler center position is off a bit (5/16") for both horizontal and vertical rulers.

    Here's the code I'm using to determine the offset positioning of the rulers.
    The window that the rulers are on has a Canvas (DesignCanvas) that has a ScrollViewer (MyScrollViewer).
    Above MyScrollViewer the horizontal ruler is placed whereby the 0 marking on the ruler is above the ScrollViewer aligned with it's top left side.
    The vertical ruler is to the left of the ScrollViewer with the 0 marking on the ruler also aligned with it's top left side.

    _rulerCenterXOffset = SystemParameters.FullPrimaryScreenWidth - MyScrollViewer.HorizontalOffset - DesignCanvas.Margin.Left  
    _rulerCenterYOffset = SystemParameters.FullPrimaryScreenWidth - MyScrollViewer.VerticalOffset - DesignCanvas.Margin.Top 


    I thought that by using the SystemParameters.FullPrimaryScreenWidth it would allow for different screen widths.

    Thanks,
    Rita

    • Edited by ritagreen Wednesday, March 18, 2009 10:52 PM
    Wednesday, March 18, 2009 10:12 PM
  • I also created a C# project with the attached code (from liangtom) in it and got it to run.
    It created a ruler above the rectangle but the position of the ruler and rectangle are hard coded.

    I'm also so curious as to how liangtom was able to place a picture of the canvas with the rectangle and the ruler above (where the xaml code is)!
    I would really like to know how to do this as a "picture is worth a 1000 words"!

    Wednesday, March 18, 2009 10:49 PM

  • It take 3 steps to upload a picture or video:


    1 Convert the video file into GIF format.

    2 Upload the gif image to a server(I use picasa ).

    3 Embed the image into the content of your thread

    • Marked as answer by Tao Liang Thursday, March 19, 2009 2:02 AM
    Thursday, March 19, 2009 2:01 AM
  • http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9499b125-f11c-460d-9c38-f230d1a18910/
    Thursday, March 19, 2009 2:03 AM
  • Great - Thanks!
    Thursday, March 19, 2009 2:35 PM
  • Here's my answer to the question regarding allowing for different screen widths with the ruler (with markings from negative values through positive values)
    so that the ruler correctly positions itself above an element at marking 0 (and not the left most negative marking) .

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dcfec4f3-ec4b-4bf3-aa39-be3e6f510064

     
    • Marked as answer by ritagreen Thursday, March 19, 2009 6:28 PM
    Thursday, March 19, 2009 6:25 PM