C# 用于位图背景图像的WPF元素,能够添加子控件
因此,我使用WinForms应用程序作为创建显示海图的WPF应用程序的指南。WinForms应用程序正在使用System.Windows.Forms.Panel并将背景图像设置为动态创建的位图。我需要在面板中添加一个子画布(或替代控件),以便显示覆盖图表的航路点 在WPF中,我曾尝试使用画布作为面板的替代品,但由于它有一个接受画笔而不是位图的背景属性,所以我无法使其正常工作 我还尝试使用WinFormsHost来利用System.Windows.Forms.Panel对象,但我不能使用它来在其中容纳另一个控件C# 用于位图背景图像的WPF元素,能够添加子控件,c#,wpf,winforms,canvas,panel,C#,Wpf,Winforms,Canvas,Panel,因此,我使用WinForms应用程序作为创建显示海图的WPF应用程序的指南。WinForms应用程序正在使用System.Windows.Forms.Panel并将背景图像设置为动态创建的位图。我需要在面板中添加一个子画布(或替代控件),以便显示覆盖图表的航路点 在WPF中,我曾尝试使用画布作为面板的替代品,但由于它有一个接受画笔而不是位图的背景属性,所以我无法使其正常工作 我还尝试使用WinFormsHost来利用System.Windows.Forms.Panel对象,但我不能使用它来在其中
所以我需要的最好是一个WPF元素,我可以不用WinFormsHost来使用它来设置位图背景图像并添加另一个覆盖了图形的控件 您可以使用ImageBrush设置背景 然而,这样做有一个很大的缺点,因为画布的大小与图像的大小不匹配。您基本上可以在画布后面使用图像:
<Grid>
<Image Source="..."/>
<Canvas ...>
</Canvas>
</Grid>
您可以使用ImageBrush设置背景 然而,这样做有一个很大的缺点,因为画布的大小与图像的大小不匹配。您基本上可以在画布后面使用图像:
<Grid>
<Image Source="..."/>
<Canvas ...>
</Canvas>
</Grid>
每当需要在WPF中显示某个内容的列表时,通常使用ItemsControl,这种情况也不例外 使用ItemsControl,您可以覆盖它使用的面板,您选择画布而不是面板是正确的。将图像设置为背景很容易,只需使用ImageBrush即可 至于您的航路点,我猜您还需要显示其他对象类型,因此为每个航路点创建一个ViewModel,并使用DataTemplate根据类型选择适当的图形。创建的每个图形都将包装在ContentPresenter中,但ItemsControl还允许您通过ItemContainerStyle覆盖该图形的样式,因此您可以在此处设置Canvas.Left和Canvas.Top来定位项目 将所有这些放在一起,您的XAML需要如下所示:
<Viewbox>
<ItemsControl ItemsSource="{Binding ChartElements}" Width="1000" Height="1000">
<ItemsControl.Resources>
<!-- DataTemplates here select the appropriate graphic to display for each class type -->
<DataTemplate DataType="{x:Type local:Waypoint}">
<Ellipse Width="50" Height="50" Fill="Yellow" Stroke="CornflowerBlue" StrokeThickness="5">
<Ellipse.RenderTransform>
<TranslateTransform X="-25" Y="-25" /> <!-- center the ellipse -->
</Ellipse.RenderTransform>
</Ellipse>
</DataTemplate>
<DataTemplate DataType="{x:Type local:NavigationLine}">
<Line X1="0" Y1="0" X2="{Binding Width}" Y2="{Binding Height}" Stroke="CornflowerBlue" StrokeThickness="10" StrokeDashArray="3 1" />
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<!-- Replace the default panel with a Canvas -->
<ItemsPanelTemplate>
<Canvas>
<Canvas.Background>
<ImageBrush ImageSource="https://images-na.ssl-images-amazon.com/images/I/A1%2Bp%2BB8wq2L._SL1500_.jpg" Stretch="Uniform" />
</Canvas.Background>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Position each item on the canvas and set the ZIndex so that waypoints appear on top -->
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
<Setter Property="Panel.ZIndex" Value="{Binding Layer}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Viewbox>
<map:Map Center="50,0" ZoomLevel="2">
<map:Map.MapLayer>
<local:ChartImageLayer />
</map:Map.MapLayer>
</map:Map>
using MapControl;
...
public class Waypoint
{
public string Label { get; set; }
public Location Location { get; set; }
}
public class ViewModel
{
public ObservableCollection<Waypoint> Waypoints { get; }
= new ObservableCollection<Waypoint>();
}
<map:Map Center="50,0" ZoomLevel="2">
...
<map:MapItemsControl ItemsSource="{Binding Waypoints}">
<map:MapItemsControl.ItemContainerStyle>
<Style TargetType="map:MapItem">
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
</Style>
</map:MapItemsControl.ItemContainerStyle>
<map:MapItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Path Fill="Red">
<Path.Data>
<EllipseGeometry RadiusX="5" RadiusY="5"/>
</Path.Data>
</Path>
<TextBlock Margin="5,-5" Text="{Binding Label}"/>
</Canvas>
</DataTemplate>
</map:MapItemsControl.ItemTemplate>
</map:MapItemsControl>
</map:Map>
您应该始终创建MainViewModel并执行适当的MVVM,但以下示例代码将帮助您开始:
public partial class MainWindow : Window
{
public List<object> ChartElements { get; } = new List<object>
{
new Waypoint{X=100, Y=100 },
new Waypoint{X=500, Y=300 },
new Waypoint{X=300, Y=500 },
new Waypoint{X=800, Y=700 },
new NavigationLine{X1=100, Y1=100, X2=500, Y2=300},
new NavigationLine{X1=500, Y1=300, X2=300, Y2=500},
new NavigationLine{X1=300, Y1=500, X2=800, Y2=700}
};
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
}
public class Waypoint
{
public int Layer { get; } = 1; // waypoint circles should always appear on top
public double X { get; set; }
public double Y { get; set; }
}
public class NavigationLine
{
public int Layer { get; } = 0;
public double X1 { get; set; }
public double Y1 { get; set; }
public double X2 { get; set; }
public double Y2 { get; set; }
public double X => this.X1;
public double Y => this.Y1;
public double Width => this.X2 - this.X1;
public double Height => this.Y2 - this.Y1;
}
公共部分类主窗口:窗口
{
公共列表ChartElements{get;}=新列表
{
新航路点{X=100,Y=100},
新航路点{X=500,Y=300},
新航路点{X=300,Y=500},
新航路点{X=800,Y=700},
新导航线{X1=100,Y1=100,X2=500,Y2=300},
新导航线{X1=500,Y1=300,X2=300,Y2=500},
新导航线{X1=300,Y1=500,X2=800,Y2=700}
};
公共主窗口()
{
初始化组件();
this.DataContext=this;
}
}
公共类航路点
{
公共整数层{get;}=1;//航路点圆应始终显示在顶部
公共双X{get;set;}
公共双Y{get;set;}
}
公共类导航线
{
公共int层{get;}=0;
公共双X1{get;set;}
公共双Y1{get;set;}
公共双X2{get;set;}
公共双Y2{get;set;}
公共双X=>this.X1;
公共双Y=>this.Y1;
公共双宽度=>this.X2-this.X1;
公共双倍高度=>this.Y2-this.Y1;
}
加载热链接图像可能需要几秒钟的时间,但您应该以以下方式结束:
每当需要在WPF中显示某个内容的列表时,通常使用ItemsControl,这种情况也不例外 使用ItemsControl,您可以覆盖它使用的面板,您选择画布而不是面板是正确的。将图像设置为背景很容易,只需使用ImageBrush即可 至于您的航路点,我猜您还需要显示其他对象类型,因此为每个航路点创建一个ViewModel,并使用DataTemplate根据类型选择适当的图形。创建的每个图形都将包装在ContentPresenter中,但ItemsControl还允许您通过ItemContainerStyle覆盖该图形的样式,因此您可以在此处设置Canvas.Left和Canvas.Top来定位项目 将所有这些放在一起,您的XAML需要如下所示:
<Viewbox>
<ItemsControl ItemsSource="{Binding ChartElements}" Width="1000" Height="1000">
<ItemsControl.Resources>
<!-- DataTemplates here select the appropriate graphic to display for each class type -->
<DataTemplate DataType="{x:Type local:Waypoint}">
<Ellipse Width="50" Height="50" Fill="Yellow" Stroke="CornflowerBlue" StrokeThickness="5">
<Ellipse.RenderTransform>
<TranslateTransform X="-25" Y="-25" /> <!-- center the ellipse -->
</Ellipse.RenderTransform>
</Ellipse>
</DataTemplate>
<DataTemplate DataType="{x:Type local:NavigationLine}">
<Line X1="0" Y1="0" X2="{Binding Width}" Y2="{Binding Height}" Stroke="CornflowerBlue" StrokeThickness="10" StrokeDashArray="3 1" />
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<!-- Replace the default panel with a Canvas -->
<ItemsPanelTemplate>
<Canvas>
<Canvas.Background>
<ImageBrush ImageSource="https://images-na.ssl-images-amazon.com/images/I/A1%2Bp%2BB8wq2L._SL1500_.jpg" Stretch="Uniform" />
</Canvas.Background>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Position each item on the canvas and set the ZIndex so that waypoints appear on top -->
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
<Setter Property="Panel.ZIndex" Value="{Binding Layer}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Viewbox>
<map:Map Center="50,0" ZoomLevel="2">
<map:Map.MapLayer>
<local:ChartImageLayer />
</map:Map.MapLayer>
</map:Map>
using MapControl;
...
public class Waypoint
{
public string Label { get; set; }
public Location Location { get; set; }
}
public class ViewModel
{
public ObservableCollection<Waypoint> Waypoints { get; }
= new ObservableCollection<Waypoint>();
}
<map:Map Center="50,0" ZoomLevel="2">
...
<map:MapItemsControl ItemsSource="{Binding Waypoints}">
<map:MapItemsControl.ItemContainerStyle>
<Style TargetType="map:MapItem">
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
</Style>
</map:MapItemsControl.ItemContainerStyle>
<map:MapItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Path Fill="Red">
<Path.Data>
<EllipseGeometry RadiusX="5" RadiusY="5"/>
</Path.Data>
</Path>
<TextBlock Margin="5,-5" Text="{Binding Label}"/>
</Canvas>
</DataTemplate>
</map:MapItemsControl.ItemTemplate>
</map:MapItemsControl>
</map:Map>
您应该始终创建MainViewModel并执行适当的MVVM,但以下示例代码将帮助您开始:
public partial class MainWindow : Window
{
public List<object> ChartElements { get; } = new List<object>
{
new Waypoint{X=100, Y=100 },
new Waypoint{X=500, Y=300 },
new Waypoint{X=300, Y=500 },
new Waypoint{X=800, Y=700 },
new NavigationLine{X1=100, Y1=100, X2=500, Y2=300},
new NavigationLine{X1=500, Y1=300, X2=300, Y2=500},
new NavigationLine{X1=300, Y1=500, X2=800, Y2=700}
};
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
}
public class Waypoint
{
public int Layer { get; } = 1; // waypoint circles should always appear on top
public double X { get; set; }
public double Y { get; set; }
}
public class NavigationLine
{
public int Layer { get; } = 0;
public double X1 { get; set; }
public double Y1 { get; set; }
public double X2 { get; set; }
public double Y2 { get; set; }
public double X => this.X1;
public double Y => this.Y1;
public double Width => this.X2 - this.X1;
public double Height => this.Y2 - this.Y1;
}
公共部分类主窗口:窗口
{
公共列表ChartElements{get;}=新列表
{
新航路点{X=100,Y=100},
新航路点{X=500,Y=300},
新航路点{X=300,Y=500},
新航路点{X=800,Y=700},
新导航线{X1=100,Y1=100,X2=500,Y2=300},
新导航线{X1=500,Y1=300,X2=300,Y2=500},
新导航线{X1=300,Y1=5