不管窗口WPF的大小如何,都将标签位置保持在图像前面(拉伸模式是统一的)

时间:2018-08-02 13:10:32

标签: c# wpf xaml

我要做的是制作一张描述内容的图片,并且图片中有一个指示符(图片已经像这样)

例如:enter image description here

我的标签将覆盖这些黄色部分

,放置它们后,无论窗口大小如何,都应保持覆盖同一部分。

我从this article开始尝试了各种方法。经过多次尝试后,这是我当前的代码,其中的问题是:

1-它应该已经遵循相同的位置,但我不认为它起作用。

2-我认为我的方法不是正确的方法,我敢肯定应该有一种更简单的方法。

首先:Window1.xaml

<Window.Resources>
    <!--
    A data-template that defines the visuals for a rectangle.
    -->
    <DataTemplate 
        DataType="{x:Type local:RectangleViewModel}"
        >
        <Grid>
            <Thumb
                Width="20"
                Height="20"
                DragDelta="Thumb_DragDelta"
                >                    
                <Thumb.Template>
                    <ControlTemplate>
                        <Border
                            Background="Blue"
                            Cursor="Hand"
                            >
                            <Viewbox>
                                <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ImageWidth ,FallbackValue=1}" />
                            </Viewbox>
                        </Border>
                    </ControlTemplate>                        
                </Thumb.Template>
            </Thumb>
        </Grid>
    </DataTemplate>
</Window.Resources>
<Window.DataContext>
    <!-- 
    Initialise the view model that supplies the UI with data.
    -->
    <local:ViewModel />
</Window.DataContext>

<Grid Background="Aqua">
    <Image Source="pack://application:,,,/Images/1111.png" SizeChanged="Image_SizeChanged" Stretch="Uniform"/>
    <!--
    This ItemsControl presents the colored rectangles.
    The data-template that defines the visuals for each rectangle is in the 
    resources section at the start of this file.
    -->
    <ItemsControl
        ItemsSource="{Binding Rectangles}"
        >
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter
                    Property="Canvas.Left"
                    Value="{Binding X}"
                    />
                <Setter
                    Property="Canvas.Top"
                    Value="{Binding Y}"
                    />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</Grid>

第二个:Window1.xaml.cs

using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;

namespace SampleCode
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            SizeChanged += Window1_SizeChanged;
        }
        /// <summary>
        /// Handle the resize of the window
        /// </summary>
        private void Window1_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Size oldSize = e.PreviousSize;

            Size newSize = e.NewSize;

            ((ViewModel)this.DataContext).Rectangles.ToList().ForEach(i => i.update(newSize));

        }
        /// <summary>
        /// Hundle the resize of the window
        /// </summary>
        private void Image_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ((ViewModel)this.DataContext).Rectangles.ToList().ForEach(i => i.ImageSize = e.NewSize);
        }
        /// <summary>
        /// Handle the user dragging the rectangle.
        /// </summary>
        private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            Thumb thumb = (Thumb)sender;
            RectangleViewModel myRectangle = (RectangleViewModel)thumb.DataContext;

            //
            // Update the the position of the rectangle in the view-model.
            //
            myRectangle.X += e.HorizontalChange;
            myRectangle.Y += e.VerticalChange;
        }
    }
}

第三:ViewModel.cs

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace SampleCode
{
    /// <summary>
    /// A simple example of a view-model.  
    /// </summary>
    public class ViewModel : INotifyPropertyChanged
    {
        #region Data Members

        /// <summary>
        /// The list of rectangles that is displayed in the ListBox.
        /// </summary>
        private ObservableCollection<RectangleViewModel> rectangles = new ObservableCollection<RectangleViewModel>();

        /// <summary>
        /// The image size
        /// </summary>
        private Size _imageSize ;

        #endregion Data Members
        public Size ImageSize
        {
            get => _imageSize; set
            {
                {
                    if (_imageSize == value)
                    {
                        return;
                    }
                    _imageSize = value;
                    OnPropertyChanged("ImageWidth");
                };
            }
        }

        public ViewModel()
        {
            // Populate the view model with some example data.
            var r1 = new RectangleViewModel();
            rectangles.Add(r1);
        }

        /// <summary>
        /// The list of rectangles that is displayed in the ListBox.
        /// </summary>
        public ObservableCollection<RectangleViewModel> Rectangles
        {
            get
            {
                return rectangles;
            }
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raises the 'PropertyChanged' event when the value of a property of the view model has changed.
        /// </summary>
        private void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        /// <summary>
        /// 'PropertyChanged' event that is raised when the value of a property of the view model has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

第四:RectangleViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Media;
using System.Windows;

namespace SampleCode
{
    /// <summary>
    /// Defines the view-model for a simple displayable rectangle.
    /// </summary>
    public class RectangleViewModel : INotifyPropertyChanged
    {
        #region Data Members

        /// <summary>
        /// The X coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        private double x;

        /// <summary>
        /// The Y coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        private double y;

        /// <summary>
        /// The size of the current window
        /// </summary>
        public Size mCurrentWindwoSize;

        #endregion Data Members

        public RectangleViewModel()
        {
        }
        /// <summary>
        /// The size of the background image
        /// </summary>
        public Size ImageSize { get; set; }

        /// <summary>
        /// The X coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        public double X
        {
            get
            {
                return (mCurrentWindwoSize.Width-ImageSize.Width)/2 + Data.x * ImageSize.Width;
            }
            set
            {
                if ((mCurrentWindwoSize.Width - ImageSize.Width) / 2 + Data.x * ImageSize.Width == value)return;
                Data.x =( value - (mCurrentWindwoSize.Width - ImageSize.Width) / 2 )/ ImageSize.Width;
                OnPropertyChanged("X");
            }
        }

        /// <summary>
        /// The Y coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        public double Y
        {
            get
            {
                return (mCurrentWindwoSize.Height - ImageSize.Height) / 2 + Data.y * ImageSize.Height;
            }
            set
            {
                if ((mCurrentWindwoSize.Height - ImageSize.Height) / 2 + Data.y * ImageSize.Height == value) return;
                Data.y = (value - (mCurrentWindwoSize.Height - ImageSize.Height) / 2) / ImageSize.Height;
                OnPropertyChanged("Y");
            }
        }

        public void update(Size size)
        {
            mCurrentWindwoSize = size;
            OnPropertyChanged("X");
            OnPropertyChanged("Y");
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raises the 'PropertyChanged' event when the value of a property of the view model has changed.
        /// </summary>
        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        /// <summary>
        /// 'PropertyChanged' event that is raised when the value of a property of the view model has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

    }
}

第五名:Data.cs

namespace SampleCode
{
    public static class Data
    {
        public static double x = 0.5;//default
        public static double y = 0.5;//default
    }
}

谢谢。

1 个答案:

答案 0 :(得分:0)

我终于做到了,

主要问题是我忘记了Windows的上面板和边框包含在ActualWidth和ActualHeight中,并且经过一些修复后,这里是最终代码:

首先:Window1.xaml

    <Window.Resources>
    <!--
    A data-template that defines the visuals for a rectangle.
    -->
    <DataTemplate 
        DataType="{x:Type local:RectangleViewModel}"
        >
        <Grid>
            <Thumb
                Width="{Binding LabelWidth}"
                Height="{Binding LabelWidth}"
                DragDelta="Thumb_DragDelta"
                >                    
                <Thumb.Template>
                    <ControlTemplate>
                        <Border 
                            Background="Blue"
                            Cursor="Hand"
                            >
                            <Viewbox>
                                <TextBlock Text="1" />
                            </Viewbox>
                        </Border>
                    </ControlTemplate>                        
                </Thumb.Template>
            </Thumb>
        </Grid>
    </DataTemplate>
</Window.Resources>
<Window.DataContext>
    <!-- 
    Initialise the view model that supplies the UI with data.
    -->
    <local:ViewModel />
</Window.DataContext>

<Grid Background="Aqua">
    <Image Source="pack://application:,,,/Images/1112.png" Stretch="Uniform"/>
    <!--
    This ItemsControl presents the colored rectangles.
    The data-template that defines the visuals for each rectangle is in the 
    resources section at the start of this file.
    -->
    <ItemsControl
        ItemsSource="{Binding Rectangles}"
        >
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas SizeChanged="Canvas_SizeChanged"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter
                    Property="Canvas.Left"
                    Value="{Binding X}"
                    />
                <Setter
                    Property="Canvas.Top"
                    Value="{Binding Y}"
                    />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</Grid>

第二个:Window1.xaml.cs

using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;

namespace SampleCode
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

        }

        /// <summary>
        /// Handle the user dragging the rectangle.
        /// </summary>
        private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            Thumb thumb = (Thumb)sender;
            RectangleViewModel myRectangle = (RectangleViewModel)thumb.DataContext;

            //
            // Update the the position of the rectangle in the view-model.
            //
            myRectangle.X += e.HorizontalChange;
            myRectangle.Y += e.VerticalChange;
        }

        /// <summary>
        /// Hundle the resize of the canvas
        /// </summary>
        private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Size newSize = e.NewSize;

            ((ViewModel)this.DataContext).Rectangles.ToList().ForEach(i => i.update(e.NewSize));

        }
    }
}

第三:ViewModel.cs

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace SampleCode
{
    /// <summary>
    /// A simple example of a view-model.  
    /// </summary>
    public class ViewModel : INotifyPropertyChanged
    {
        #region Data Members

        /// <summary>
        /// The list of rectangles that is displayed in the ListBox.
        /// </summary>
        private ObservableCollection<RectangleViewModel> rectangles = new ObservableCollection<RectangleViewModel>();

        #endregion

        public ViewModel()
        {
            // Populate the view model with some example data.
            var r1 = new RectangleViewModel(0.1,0.3);
            rectangles.Add(r1);

            var r2 = new RectangleViewModel(0.2,0.4);
            rectangles.Add(r2);

        }

        /// <summary>
        /// The list of rectangles that is displayed in the ListBox.
        /// </summary>
        public ObservableCollection<RectangleViewModel> Rectangles
        {
            get
            {
                return rectangles;
            }
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raises the 'PropertyChanged' event when the value of a property of the view model has changed.
        /// </summary>
        private void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        /// <summary>
        /// 'PropertyChanged' event that is raised when the value of a property of the view model has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

最后,第四点:RectabgleViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Media;
using System.Windows;

namespace SampleCode
{
    /// <summary>
    /// Defines the view-model for a simple displayable rectangle.
    /// </summary>
    public class RectangleViewModel : INotifyPropertyChanged
    {
        #region Data Members

        /// <summary>
        /// The aspect ration of the image
        /// </summary>
        private double ratio = 1.375;

        /// <summary>
        /// The label width
        /// </summary>
        private double mLabelWidth = 20;

        /// <summary>
        /// The X coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        private double mX;

        /// <summary>
        /// The Y coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        private double mY;

        /// <summary>
        /// The size of the current window
        /// </summary>
        public Size mCurrentWindwoSize = new Size(450,300);

        /// <summary>
        /// The size of the label as a percantage from the image size
        /// </summary>
        private readonly double sizePercentage = 0.05;

        #endregion Data Members

        public RectangleViewModel(double x, double y)
        {
            mX = x;
            mY = y;
        }
        /// <summary>
        /// The size of the background image
        /// </summary>
        public Size ImageSize { get; set; }

        /// <summary>
        /// The width of the label
        /// </summary>
        public double LabelWidth
        {
            get { return mLabelWidth; }
            set { if (value == mLabelWidth)
                    return;
                else
                    mLabelWidth = value;
                OnPropertyChanged("LabelWidth");
            }
        }

        /// <summary>
        /// The X coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        public double X
        {
            get
            {
                return (mCurrentWindwoSize.Width-ImageSize.Width)/2 + mX * ImageSize.Width - mLabelWidth/2;
            }
            set
            {
                //if ((mCurrentWindwoSize.Width - ImageSize.Width) / 2 + mX * ImageSize.Width == value)return;
                mX =( value - (mCurrentWindwoSize.Width - ImageSize.Width) / 2 + mLabelWidth/2)/ ImageSize.Width;
                OnPropertyChanged("X");
            }
        }

        /// <summary>
        /// The Y coordinate of the location of the rectangle (in content coordinates).
        /// </summary>
        public double Y
        {
            get
            {
                return (mCurrentWindwoSize.Height - ImageSize.Height) / 2 + mY * ImageSize.Height - mLabelWidth/2 ;
            }
            set
            {
                //if ((mCurrentWindwoSize.Height - ImageSize.Height) / 2 + mY * ImageSize.Height == value) return;
                mY = (value - (mCurrentWindwoSize.Height - ImageSize.Height) / 2 + mLabelWidth/2) / ImageSize.Height;
                OnPropertyChanged("Y");
            }
        }

        public void update(Size windowSize)
        {
            mCurrentWindwoSize = windowSize;

            if (windowSize.Height > windowSize.Width * ratio)
            {
                ImageSize = new Size(windowSize.Width, windowSize.Width * ratio);
            }
            else
            {
                ImageSize = new Size(windowSize.Height / ratio, windowSize.Height);
            }

            LabelWidth = ImageSize.Width * sizePercentage;

            X = (mCurrentWindwoSize.Width - ImageSize.Width) / 2 + mX * ImageSize.Width - mLabelWidth/2;

            Y = (mCurrentWindwoSize.Height - ImageSize.Height) / 2 + mY * ImageSize.Height - mLabelWidth/2;
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raises the 'PropertyChanged' event when the value of a property of the view model has changed.
        /// </summary>
        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        /// <summary>
        /// 'PropertyChanged' event that is raised when the value of a property of the view model has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

    }
}

我认为它仍然需要一些清理,但是至少它可以完成它所要求的工作。 在将其移至实际项目时,我将尝试使其更整洁。

谢谢。