我要做的是制作一张描述内容的图片,并且图片中有一个指示符(图片已经像这样)
例如: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
}
}
谢谢。
答案 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
}
}
我认为它仍然需要一些清理,但是至少它可以完成它所要求的工作。 在将其移至实际项目时,我将尝试使其更整洁。
谢谢。