- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试转换 System.Windows.Shapes.Shape对象变成 System.Windows.Media.Geometry目的。
与 Geometry
对象,我将根据一组数据点使用自定义图形控件多次呈现它。这要求 Geometry
的每个实例对象具有唯一的 TranslateTransform
目的。
现在,我正在以两种不同的方式解决这个问题,但似乎都没有正常工作。我的自定义控件使用以下代码来绘制几何图形:
//Create an instance of the geometry the shape uses.
Geometry geo = DataPointShape.RenderedGeometry.Clone();
//Apply transformation.
TranslateTransform translation = new TranslateTransform(dataPoint.X, dataPoint.Y);
geo.Transform = translation;
//Create pen and draw geometry.
Pen shapePen = new Pen(DataPointShape.Stroke, DataPointShape.StrokeThickness);
dc.DrawGeometry(DataPointShape.Fill, shapePen, geo);
//Create an instance of the geometry the shape uses.
Geometry geo = DataPointShape.RenderedGeometry;
//Apply transformation.
TranslateTransform translation = new TranslateTransform(dataPoint.X, dataPoint.Y);
dc.PushTransform(translation);
//Create pen and draw geometry.
Pen shapePen = new Pen(DataPointShape.Stroke, DataPointShape.StrokeThickness);
dc.DrawGeometry(DataPointShape.Fill, shapePen, geo);
dc.Pop(); //Undo translation.
EDIT:
I have figured out how to generate the appearance of the geometry. But this only works in design-mode. Execute these steps:
- Rebuild project.
- Go to MainWindow.xaml and click in the custom shape object so that the shape's properties load into Visual Studio's property window. Wait until the property window renders what the shape looks like.
- Modify the data points collection or properties to see the geometry rendered properly.
Here is what I want the control to ultimately look like for now:
Shape
的方法中存在哪些问题。反对
Geometry
目的。
<Window x:Class="CustomControls.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControls">
<Grid>
<local:LineGraph>
<local:LineGraph.DataPointShape>
<Ellipse Width="10" Height="10" Fill="Red" Stroke="Black" StrokeThickness="1" />
</local:LineGraph.DataPointShape>
<local:LineGraph.DataPoints>
<local:DataPoint X="10" Y="10"/>
<local:DataPoint X="20" Y="20"/>
<local:DataPoint X="30" Y="30"/>
<local:DataPoint X="40" Y="40"/>
</local:LineGraph.DataPoints>
</local:LineGraph>
</Grid>
public class DataPoint : DependencyObject, INotifyPropertyChanged
{
public static readonly DependencyProperty XProperty = DependencyProperty.Register("XProperty", typeof(double), typeof(DataPoint), new FrameworkPropertyMetadata(0.0d, DataPoint_PropertyChanged));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("YProperty", typeof(double), typeof(DataPoint), new FrameworkPropertyMetadata(0.0d, DataPoint_PropertyChanged));
private static void DataPoint_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
DataPoint dp = (DataPoint)sender;
dp.RaisePropertyChanged(e.Property.Name);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public double X
{
get { return (double)GetValue(XProperty); }
set { SetValue(XProperty, (double)value); }
}
public double Y
{
get { return (double)GetValue(YProperty); }
set { SetValue(YProperty, (double)value); }
}
}
public class LineGraph : FrameworkElement
{
public static readonly DependencyProperty DataPointShapeProperty = DependencyProperty.Register("DataPointShapeProperty", typeof(Shape), typeof(LineGraph), new FrameworkPropertyMetadata(default(Shape), FrameworkPropertyMetadataOptions.AffectsRender, DataPointShapeChanged));
public static readonly DependencyProperty DataPointsProperty = DependencyProperty.Register("DataPointsProperty", typeof(ObservableCollection<DataPoint>), typeof(LineGraph), new FrameworkPropertyMetadata(default(ObservableCollection<DataPoint>), FrameworkPropertyMetadataOptions.AffectsRender, DataPointsChanged));
private static void DataPointShapeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
LineGraph g = (LineGraph)sender;
g.InvalidateVisual();
}
private static void DataPointsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{ //Collection referenced set or unset.
LineGraph g = (LineGraph)sender;
INotifyCollectionChanged oldValue = e.OldValue as INotifyCollectionChanged;
INotifyCollectionChanged newValue = e.NewValue as INotifyCollectionChanged;
if (oldValue != null)
oldValue.CollectionChanged -= g.DataPoints_CollectionChanged;
if (newValue != null)
newValue.CollectionChanged += g.DataPoints_CollectionChanged;
//Update the point visuals.
g.InvalidateVisual();
}
private void DataPoints_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{ //Collection changed (added/removed from).
if (e.OldItems != null)
foreach (INotifyPropertyChanged n in e.OldItems)
{
n.PropertyChanged -= DataPoint_PropertyChanged;
}
if (e.NewItems != null)
foreach (INotifyPropertyChanged n in e.NewItems)
{
n.PropertyChanged += DataPoint_PropertyChanged;
}
InvalidateVisual();
}
private void DataPoint_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//Re-render the LineGraph when a DataPoint has a property that changes.
InvalidateVisual();
}
public Shape DataPointShape
{
get { return (Shape)GetValue(DataPointShapeProperty); }
set { SetValue(DataPointShapeProperty, (Shape)value); }
}
public ObservableCollection<DataPoint> DataPoints
{
get { return (ObservableCollection<DataPoint>)GetValue(DataPointsProperty); }
set { SetValue(DataPointsProperty, (ObservableCollection<DataPoint>)value); }
}
public LineGraph()
{ //Provide instance-specific value for data point collection instead of a shared static instance.
SetCurrentValue(DataPointsProperty, new ObservableCollection<DataPoint>());
}
protected override void OnRender(DrawingContext dc)
{
if (DataPointShape != null)
{
Pen shapePen = new Pen(DataPointShape.Stroke, DataPointShape.StrokeThickness);
foreach (DataPoint dp in DataPoints)
{
Geometry geo = DataPointShape.RenderedGeometry.Clone();
TranslateTransform translation = new TranslateTransform(dp.X, dp.Y);
geo.Transform = translation;
dc.DrawGeometry(DataPointShape.Fill, shapePen, geo);
}
}
}
}
EDIT 2:
In response to this answer by Peter Duniho, I would like to provide the alternate method to lying to Visual Studio in creating a custom control. For creating the custom control execute these steps:
- Create folder in root of project named
Themes
- Create resource dictionary in
Themes
folder namedGeneric.xaml
- Create a style in the resource dictionary for the control.
- Apply the style from the control's C# code.
Generic.xaml
Here is an example of for theSimpleGraph
described by Peter.<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControls">
<Style TargetType="local:SimpleGraph" BasedOn="{StaticResource {x:Type ItemsControl}}">
<Style.Resources>
<EllipseGeometry x:Key="defaultGraphGeometry" Center="5,5" RadiusX="5" RadiusY="5"/>
</Style.Resources>
<Style.Setters>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type local:DataPoint}">
<Path Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:SimpleGraph}}, Path=DataPointFill}"
Stroke="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:SimpleGraph}}, Path=DataPointStroke}"
StrokeThickness="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:SimpleGraph}}, Path=DataPointStrokeThickness}"
Data="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:SimpleGraph}}, Path=DataPointGeometry}">
<Path.RenderTransform>
<TranslateTransform X="{Binding X}" Y="{Binding Y}"/>
</Path.RenderTransform>
</Path>
</DataTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</ResourceDictionary>Lastly, apply the style like so in the
SimpleGraph
constructor:public SimpleGraph()
{
DefaultStyleKey = typeof(SimpleGraph);
DataPointGeometry = (Geometry)FindResource("defaultGraphGeometry");
}
最佳答案
我认为你可能没有以最好的方式解决这个问题。根据您发布的代码,您似乎正在尝试手动执行 WPF 在自动处理方面相当擅长的事情。
主要的棘手部分(至少对我来说……我几乎不是 WPF 专家)是您似乎想要使用实际的 Shape
对象作为图形数据点图形的模板,我不完全确定允许以编程方式或声明方式替换该模板而不暴露控制图形定位的底层转换机制的最佳方法。
因此,这是一个忽略该特定方面的示例(我将在下面评论替代方案),但我相信它可以满足您的确切需求。
首先,我创建了一个自定义 ItemsControl
类(在 Visual Studio 中,我通过撒谎并告诉 VS 我想添加一个 UserControl
来做到这一点,这让我在项目中获得了一个基于 XAML 的项目......我立即在两个 .xaml 中将“UserControl”替换为“ItemsControl”和 .xaml.cs 文件):
XAML:
<ItemsControl x:Class="TestSO28332278SimpleGraphControl.SimpleGraph"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestSO28332278SimpleGraphControl"
mc:Ignorable="d"
x:Name="root"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl.Resources>
<EllipseGeometry x:Key="defaultGraphGeometry" Center="5,5" RadiusX="5" RadiusY="5" />
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:DataPoint}">
<Path Data="{Binding ElementName=root, Path=DataPointGeometry}"
Fill="Red" Stroke="Black" StrokeThickness="1">
<Path.RenderTransform>
<TranslateTransform X="{Binding X}" Y="{Binding Y}"/>
</Path.RenderTransform>
</Path>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public partial class SimpleGraph : ItemsControl
{
public Geometry DataPointGeometry
{
get { return (Geometry)GetValue(DataPointShapeProperty); }
set { SetValue(DataPointShapeProperty, value); }
}
public static DependencyProperty DataPointShapeProperty = DependencyProperty.Register(
"DataPointGeometry", typeof(Geometry), typeof(SimpleGraph));
public SimpleGraph()
{
InitializeComponent();
DataPointGeometry = (Geometry)FindResource("defaultGraphGeometry");
}
}
ItemsControl
具有默认
ItemTemplate
的类有一个
Path
目的。该对象的几何图形绑定(bind)到控件
DataPointGeometry
属性(property)及其
RenderTransform
绑定(bind)到数据项的
X
和
Y
值作为平移变换的偏移量。
Canvas
用于
ItemsPanel
,因为我只需要一个地方来绘制东西,没有任何其他布局功能。最后,有一个资源定义了要使用的默认几何图形,以防调用者不提供。
<Window x:Class="TestSO28332278SimpleGraphControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestSO28332278SimpleGraphControl"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<PathGeometry x:Key="dataPointGeometry"
Figures="M 0.5000,0.0000
L 0.6176,0.3382
0.9755,0.3455
0.6902,0.5618
0.7939,0.9045
0.5000,0.7000
0.2061,0.9045
0.3098,0.5618
0.0245,0.3455
0.3824,0.3382 Z">
<PathGeometry.Transform>
<ScaleTransform ScaleX="20" ScaleY="20" />
</PathGeometry.Transform>
</PathGeometry>
</Window.Resources>
<Grid>
<Border Margin="3" BorderBrush="Black" BorderThickness="1">
<local:SimpleGraph Width="450" Height="300" DataPointGeometry="{StaticResource dataPointGeometry}">
<local:SimpleGraph.Items>
<local:DataPoint X="10" Y="10" />
<local:DataPoint X="25" Y="25" />
<local:DataPoint X="40" Y="40" />
<local:DataPoint X="55" Y="55" />
</local:SimpleGraph.Items>
</local:SimpleGraph>
</Border>
</Grid>
</Window>
PathGeometry
资源,然后将该资源绑定(bind)到控件的
DataPointGeometry
属性(property)。这允许程序为图形提供自定义几何图形。
DataPoint
的任何值对象发生变化,或者数据集合本身被修改,图表将自动更新。
Path
对象的方式类似于 DataPointGeometry
属性(property)。例如。 DataPointFill
, DataPointStroke
等Shape
对象,然后使用该对象的属性来填充绑定(bind)到模板对象属性的特定属性。这主要是为调用者提供方便;如果有的话,这在图形控件本身中会增加一些复杂性。 Shape
对象,然后您可以使用 XamlWriter
将其转换为模板要为对象创建一些 XAML,请添加必要的 Transform
XAML 中的元素并将其包装在 DataTemplate
中声明(例如,通过将 XAML 作为内存中的 DOM 加载来修改 XAML),然后使用 XamlReader
然后将 XAML 作为模板加载,然后您可以将其分配给 ItemTemplate
属性(property)。 关于c# - 在 WPF 中将形状转换为可重用的几何图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28332278/
这个问题在这里已经有了答案: How to initialize var? (11 个答案) 关闭 8 年前。 我想给一个变量赋初值 null,并在下一个 if-else block 中赋值,但是编
我正在使用 TypeScript 3.8 编写 JS 和 TS 混合的代码。我写了以下行: export * as Easing from './easing'; 应该是 fair game在 Typ
我需要将 R 代码中的“/”更改为“\”。我有这样的事情: tmp <- paste(getwd(),"tmp.xls",sep="/") 所以我的 tmp是 c:/Study/tmp.xls 我希望
我有个问题。例如我有这个: id truth count 1 1 1 2 1 2 3 0 0 4 1 1 5 1 2 6 1
我正在尝试使用“IN”和“=”来查找一些 bean。我目前正在使用此代码: $ids = array(1,2,3,4); $user = 1; $things = R::find( 'thing'
是否可以在 Xcode 中部署到其他人的手机上?我没有 iPhone,但我想测试我在 friend 手机上制作的应用程序。在我支付 99 美元之前,我想确保这不会造成麻烦。 谢谢。 最佳答案 不会有任
我试图得到一个非常大的数字(超过 unsigned long long int )。所以我把它作为一个字符串,然后一个数字一个数字地转换成整数并使用它。 #include #include int
我在 Rust 中有 C 语言库的绑定(bind),但它们并不完整。 在 C 代码中,我定义了一个简化的宏,如下所示: #define MY_MACROS1(PTR) (((my_struct1
我正在努力解决这个问题。 http://jsfiddle.net/yhcqfy44/ 动画应该自动相对于 滚动到顶部每次出现滚动条时的高度。 我已经写了这个,但没有运气: var hheight =
我正在处理一个将数字作为字符串返回的 JSON API。例如 "12" ,但是,该字段值也可以是非数字的,例如:"-" . 我已将 JSON 数据解析为映射,我想将此字段提取为 elixir 中的整数
我正在尝试编写一个类,将.wav文件转换为.aiff文件作为项目的一部分。 我遇到了几个库Alvas.Audio(http://alvas.net/alvas.audio,overview.aspx)
我想在 Lucene 中将像“New York”这样的“复合词”索引为单个术语,而不是像“new”、“york”那样。这样,如果有人搜索“new place”,则包含“new york”的文档将不会匹
我希望这个解释能让我更好地了解使用宏的优点。 最佳答案 在函数中,所有参数在调用之前都会被评估。 这意味着 or 作为函数不能是惰性的,而宏可以将 or 重写为 if 语句,该语句仅在以下情况下计算分
我有一些看起来像这样的 XML foo ]]> (注意 > 登录 "> foo")和 XSLT 样式表 当我运行xsltproc stylesheet.xs
当我尝试将 Any 转换为 List 时,如下面的示例所示,我得到“Unchecked cast: Any!”到列表'警告。有没有解决此类问题的方法? val x: List = objectOfTy
我正在使用 Python 开发一个简单的爬虫。目的是创建一个 sitemap.xml。(你可以在这里找到真正的 alpha 版本:http://code.google.com/p/sitemappy/
我想知道在 VBScript 中是否可以在多行中中断 If 语句。喜欢: If (UCase(Trim(objSheet.Cells(i, a).Value)) = "YES") Or _ (UCas
for (String item : someList) { System.out.println(item); } 使用“do while”是否等效? 谢谢。 最佳答案 如果列表为空,f
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Split string with delimiters in C 在 C 中将“,”分隔的列表拆分为数组的最佳方法
我有一个如下所示的字符数组: [0, 10, 20, 30, 670] 如何将此字符串转换为整数数组? 这是我的数组 int i=0; size_t dim = 1; char* array = (c
我是一名优秀的程序员,十分优秀!