WPF - 用图钉标记图像
WPF - Marking an image with pushpins
- 我需要在 WPF 应用程序中显示图像(固定大小)。
- 如上图应该可以用图钉标记图片
图片。
- 它应该能够为每个图钉添加描述,并且在悬停时
在图钉上应显示说明。
- 最后我需要将所有信息保存在SQL数据库中才能显示
再次别针。
是否可以通过创建自定义控件来实现?
请向我建议您实施此解决方案的想法。
提供示例将不胜感激。
回答你的问题:是的,这是可能的。
在使用 WPF 时,我强烈推荐 MVVM 体系结构模式。您需要的是:
- 一个canvas控件为了使用绝对定位
- 将显示背景图像的 image 控件
- 将显示图钉图像的自定义图钉控件。此控件还可以包含将用于生成描述控件的 DataTemplate。
- 将显示有关 pin 的信息的自定义控件(将在弹出窗口中使用)
- 一个 adorner 将在装饰层中呈现 pin 信息弹出窗口。将装饰器装饰器放置在与 canvas.
相同的位置
您需要存储的关于 pin 的信息:
- 它的 Canvas.Top 和 Canvas.Left 值
- 影响其视觉特征(例如图像、颜色等)的属性
- 弹出窗口中显示的信息(例如描述、图片)
然后您可以从数据库中读取所有条目并为每个条目创建一个 pin 视图模型并将视图模型绑定到 canvas 中的项目控件。不要忘记将 pin 控件的属性绑定到其视图模型的相应值(例如 Canvas.Left、Canvas.Top、描述等)。
至于弹出窗口,一旦您创建了装饰器 class,当您需要显示弹出窗口时,将其实例添加到 canvas 的装饰层,并在需要时将其删除关闭弹出窗口。
地图控件样式的示例如下所示(假设地图控件的视图模型包含可观察的引脚集合):
<Style TargetType="{x:Type local:Map}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Map}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<AdornerDecorator></AdornerDecorator>
<ItemsControl ItemsSource="{Binding Path=Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:Pin></local:Pin>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这是一个简单呈现给定 FrameworkElement 的装饰器控件示例:
public class ControlAdorner : Adorner {
FrameworkElement _control;
public FrameworkElement Control {
get {
return (_control);
}
set {
_control = value;
}
}
public ControlAdorner(UIElement Element, FrameworkElement Control)
: base(Element) {
this.Control = Control;
this.AddVisualChild(this.Control);
this.IsHitTestVisible = false;
}
protected override Visual GetVisualChild(int index) {
if (index != 0) throw new ArgumentOutOfRangeException();
return _control;
}
protected override int VisualChildrenCount {
get {
return 1;
}
}
public void UpdatePosition(Point point) {
VisualOffset = new Vector(point.X, point.Y);
this.InvalidateVisual();
}
protected override Size MeasureOverride(Size constraint) {
Control.Measure(constraint);
return Control.DesiredSize;
}
protected override Size ArrangeOverride(Size finalSize) {
Control.Arrange(new Rect(new Point(VisualOffset.X, VisualOffset.Y - 20), finalSize));
return new Size(Control.ActualWidth, Control.ActualHeight);
}
}
下面是如何让 Pin 控件在鼠标悬停时显示装饰器:
public class Pin : Control {
public DataTemplate DescriptionItemTemplate {
get { return (DataTemplate)GetValue(DescriptionItemTemplateProperty); }
set { SetValue(DescriptionItemTemplateProperty, value); }
}
public static readonly DependencyProperty DescriptionItemTemplateProperty =
DependencyProperty.Register("DescriptionItemTemplate", typeof(DataTemplate), typeof(Pin), new PropertyMetadata(null));
ControlAdorner _adorner;
AdornerLayer _adornerLayer;
static Pin() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(Pin), new FrameworkPropertyMetadata(typeof(Pin)));
}
public Pin() {
this.MouseEnter += Pin_MouseEnter;
this.MouseLeave += Pin_MouseLeave;
}
private void Pin_MouseEnter(object sender, MouseEventArgs e) {
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
FrameworkElement element = DescriptionItemTemplate.LoadContent() as FrameworkElement;
if (element == null) { return; }
element.DataContext = this.DataContext;
_adorner = new ControlAdorner(this, element);
_adornerLayer.Add(_adorner);
}
private void Pin_MouseLeave(object sender, MouseEventArgs e) {
_adornerLayer.Remove(_adorner);
_adorner = null;
}
}
- 我需要在 WPF 应用程序中显示图像(固定大小)。
- 如上图应该可以用图钉标记图片 图片。
- 它应该能够为每个图钉添加描述,并且在悬停时 在图钉上应显示说明。
- 最后我需要将所有信息保存在SQL数据库中才能显示 再次别针。
是否可以通过创建自定义控件来实现? 请向我建议您实施此解决方案的想法。 提供示例将不胜感激。
回答你的问题:是的,这是可能的。
在使用 WPF 时,我强烈推荐 MVVM 体系结构模式。您需要的是:
- 一个canvas控件为了使用绝对定位
- 将显示背景图像的 image 控件
- 将显示图钉图像的自定义图钉控件。此控件还可以包含将用于生成描述控件的 DataTemplate。
- 将显示有关 pin 的信息的自定义控件(将在弹出窗口中使用)
- 一个 adorner 将在装饰层中呈现 pin 信息弹出窗口。将装饰器装饰器放置在与 canvas. 相同的位置
您需要存储的关于 pin 的信息:
- 它的 Canvas.Top 和 Canvas.Left 值
- 影响其视觉特征(例如图像、颜色等)的属性
- 弹出窗口中显示的信息(例如描述、图片)
然后您可以从数据库中读取所有条目并为每个条目创建一个 pin 视图模型并将视图模型绑定到 canvas 中的项目控件。不要忘记将 pin 控件的属性绑定到其视图模型的相应值(例如 Canvas.Left、Canvas.Top、描述等)。
至于弹出窗口,一旦您创建了装饰器 class,当您需要显示弹出窗口时,将其实例添加到 canvas 的装饰层,并在需要时将其删除关闭弹出窗口。
地图控件样式的示例如下所示(假设地图控件的视图模型包含可观察的引脚集合):
<Style TargetType="{x:Type local:Map}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Map}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<AdornerDecorator></AdornerDecorator>
<ItemsControl ItemsSource="{Binding Path=Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:Pin></local:Pin>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这是一个简单呈现给定 FrameworkElement 的装饰器控件示例:
public class ControlAdorner : Adorner {
FrameworkElement _control;
public FrameworkElement Control {
get {
return (_control);
}
set {
_control = value;
}
}
public ControlAdorner(UIElement Element, FrameworkElement Control)
: base(Element) {
this.Control = Control;
this.AddVisualChild(this.Control);
this.IsHitTestVisible = false;
}
protected override Visual GetVisualChild(int index) {
if (index != 0) throw new ArgumentOutOfRangeException();
return _control;
}
protected override int VisualChildrenCount {
get {
return 1;
}
}
public void UpdatePosition(Point point) {
VisualOffset = new Vector(point.X, point.Y);
this.InvalidateVisual();
}
protected override Size MeasureOverride(Size constraint) {
Control.Measure(constraint);
return Control.DesiredSize;
}
protected override Size ArrangeOverride(Size finalSize) {
Control.Arrange(new Rect(new Point(VisualOffset.X, VisualOffset.Y - 20), finalSize));
return new Size(Control.ActualWidth, Control.ActualHeight);
}
}
下面是如何让 Pin 控件在鼠标悬停时显示装饰器:
public class Pin : Control {
public DataTemplate DescriptionItemTemplate {
get { return (DataTemplate)GetValue(DescriptionItemTemplateProperty); }
set { SetValue(DescriptionItemTemplateProperty, value); }
}
public static readonly DependencyProperty DescriptionItemTemplateProperty =
DependencyProperty.Register("DescriptionItemTemplate", typeof(DataTemplate), typeof(Pin), new PropertyMetadata(null));
ControlAdorner _adorner;
AdornerLayer _adornerLayer;
static Pin() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(Pin), new FrameworkPropertyMetadata(typeof(Pin)));
}
public Pin() {
this.MouseEnter += Pin_MouseEnter;
this.MouseLeave += Pin_MouseLeave;
}
private void Pin_MouseEnter(object sender, MouseEventArgs e) {
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
FrameworkElement element = DescriptionItemTemplate.LoadContent() as FrameworkElement;
if (element == null) { return; }
element.DataContext = this.DataContext;
_adorner = new ControlAdorner(this, element);
_adornerLayer.Add(_adorner);
}
private void Pin_MouseLeave(object sender, MouseEventArgs e) {
_adornerLayer.Remove(_adorner);
_adorner = null;
}
}