C# WPF在没有第三方库的情况下,有没有更好的方法进行2D制图?

C# WPF在没有第三方库的情况下,有没有更好的方法进行2D制图?,c#,wpf,mvvm,charts,C#,Wpf,Mvvm,Charts,我想做一个项目,为图表制作一个非常通用的可重用用户控件,这个控件几乎没有任何形式。我本来希望在制图方面有所收获,但似乎这个星球上几乎每个人都使用WPF工具包或Sparrow图表作为免费的第三方方法来制作图表。有没有人有过绑定或构建完全独立的制图方法的经验?我在考虑做一些通用的事情,比如在画布上绑定一条多段线并传递。我很好奇是否还有其他人在这条路上走过,并且有为事件引发和潜在依赖属性设置绑定的技巧。我曾考虑采用MVVM体系结构方法,并将大部分绑定到ViewModel,但我最终希望公开属性以进行更新

我想做一个项目,为图表制作一个非常通用的可重用用户控件,这个控件几乎没有任何形式。我本来希望在制图方面有所收获,但似乎这个星球上几乎每个人都使用WPF工具包或Sparrow图表作为免费的第三方方法来制作图表。有没有人有过绑定或构建完全独立的制图方法的经验?我在考虑做一些通用的事情,比如在画布上绑定一条多段线并传递。我很好奇是否还有其他人在这条路上走过,并且有为事件引发和潜在依赖属性设置绑定的技巧。我曾考虑采用MVVM体系结构方法,并将大部分绑定到ViewModel,但我最终希望公开属性以进行更新

与此概念类似(UserControl嵌入到另一个视图或MainForm中):

以后编辑

我还尝试过做一个绑定到类的模板控件

 <Style TargetType="{x:Type local:LineGraph}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:LineGraph}">
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
          </Grid.RowDefinitions>
          <TextBlock Grid.Row="0" Text="Hello" FontSize="20"/>
          <Border Grid.Row="1" BorderThickness="1" BorderBrush="Black" CornerRadius="15" Margin="10">
            <Canvas Margin="10" x:Name="PART_Canvas">
              <Canvas.LayoutTransform>
                <ScaleTransform ScaleX="1" ScaleY="-1" />
              </Canvas.LayoutTransform>
            </Canvas>
          </Border>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

类(其中一些需要清理,因为我正在使用其他人的实现,它在VB.NET中并已转换):

公共类线条图:控件,INotifyPropertyChanged
{
//建造师
静态线图()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LineGraph)),new FrameworkPropertyMetadata(typeof(LineGraph));
}
公共事件PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
公共void OnPropertyChanged(字符串信息)
{
if(PropertyChanged!=null){
PropertyChanged(此,新PropertyChangedEventArgs(信息));
}
}
public static readonly dependencProperty\u Trends=dependencProperty.RegisterReadOnly(“趋势”、类型(集合)、类型(线条图)、新属性元数据(新集合())。dependencProperty;
公众募捐趋势{
获取{return(Collection)GetValue(_Trends);}
}
应用程序模板()上的公共重写无效
{
base.OnApplyTemplate();
动态画布=GetTemplateChild(“PART_画布”)作为画布;
如果(画布!=null&&Trends!=null){
foreach(趋势中的无效趋势变量){
趋势=趋势变量;
DrawTrend(画布、趋势);
}
}
}
私有void DrawTrend(画布drawingCanvas、ChartDataSegment Trend)
{
动态t=趋势图数据段;
如果(t!=null和&t.点!=null){

对于(inti=1;i是的,您可以创建一个图表控件,一个带有一种“图表”的简单控件,当你想扩展这段代码时,真正的工作就开始了,然后你必须记住,在某个时候,你的需求可能会改变,你开始的设计将不再是好的。我个人认为这将是一个很好的练习。但你需要记住,你将收到的数据会改变,没有人会愿意传递
点的集合
s,我个人希望传递整数、浮点数或小数的集合。几乎任何我喜欢的都可以。在这一点上,你将开始绞尽脑汁,重新思考实现所有逻辑的另一种方法。这是我接下来几个月的朋友。我不想泄气您不愿意接受这项任务,但您的出发点在不久的将来肯定会改变。

顺便说一句,听威尔说,他知道他在说什么。

我制作了一个我需要的特定类型的图形,和你一样,我没有使用任何第三方库。我正在寻找它,我发现这个项目:

他们制作了一个类似于以下内容的图表:

这些源代码可供下载,并且不使用第三方代码,因此您可以轻松查看它们所做的一切

要创建图形,只需执行以下操作:

<WpfCharts:SpiderChart Title="Spider chart"  
                   Lines="{Binding Lines}" 
                   Axis="{Binding Axes}" 
                   Minimum="0" 
                   Maximum="1" 
                   Ticks="5" 
                   ShowLegend="True" 
                   LegendLocation="BottomRight" 
                   LegendBackgroundColor="Aquamarine"/> 

正如你所看到的,它已经绑定了属性。我已经在MVVM项目中使用它了


我希望它能引导你找到你想要的东西。

这真的不是主题。很难找到是/否的问题。如果你从未做过任何UI工作,这很难。因此,除非你想至少花几个月的时间在它上面,否则就买一个第三方库。它们很昂贵,因为离婚很昂贵。所以这是:“我的直接问题,因为堆栈溢出需要有关问题的详细信息:“您能轻松地插入集合(点)的集合(线)并使用具有从属属性的画布进行自我更新吗?”不具体?哪一部分不够具体?不是势利,只是有标准。我在底部读到了,但如果我添加一个回答“是”或“否”,对你有什么好处?你怎么知道我是对的?见鬼,根据我的经验,我可以告诉你,按照你的要求去做很容易,但这只是触及控制设计的表面。但话说回来,也许我只是很差劲,你会发现这很容易。这就是为什么你的问题不在主题上的原因。把问题的某些部分加粗并不能说明这是不正确的。威尔不是吗除了“编码很难,请使用第三方”之外,不要给出其他答案。如果我能制作一个图表并绑定到它(我的图表工作得很好,我在上面给出了)我只需要再多做几步,看看是否可以通过API或其他方式轻松地对其进行自我更新。我知道这是一个有趣的问题,但这就是我提出问题的原因。这让我有点不安,因为它变得越来越模糊了:“太模糊了!!!你开始询问有关架构选择和技术以及2+2=?”.如果我知道怎么做,我就不会在这里了。我开始对自我更新很好奇。我也不知道这是什么,但这种“过于模糊”的狂热正在加剧
 <Style TargetType="{x:Type local:LineGraph}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:LineGraph}">
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
          </Grid.RowDefinitions>
          <TextBlock Grid.Row="0" Text="Hello" FontSize="20"/>
          <Border Grid.Row="1" BorderThickness="1" BorderBrush="Black" CornerRadius="15" Margin="10">
            <Canvas Margin="10" x:Name="PART_Canvas">
              <Canvas.LayoutTransform>
                <ScaleTransform ScaleX="1" ScaleY="-1" />
              </Canvas.LayoutTransform>
            </Canvas>
          </Border>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
public class LineGraph : Control, INotifyPropertyChanged
{

    //CONSTRUCTOR
    static LineGraph()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(LineGraph), new FrameworkPropertyMetadata(typeof(LineGraph)));
    }

    public event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

    public void OnPropertyChanged(string info)
    {
        if (PropertyChanged != null) {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }


    public static readonly DependencyProperty _Trends = DependencyProperty.RegisterReadOnly("Trends", typeof(Collection<ChartDataSegment>), typeof(LineGraph), new PropertyMetadata(new Collection<ChartDataSegment>())).DependencyProperty;
    public Collection<ChartDataSegment> Trends {
        get { return (Collection<ChartDataSegment>)GetValue(_Trends); }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        dynamic canvas = GetTemplateChild("PART_Canvas") as Canvas;
        if (canvas != null && Trends != null) {
            foreach (void trend_loopVariable in Trends) {
                trend = trend_loopVariable;
                DrawTrend(canvas, trend);
            }
        }
    }

    private void DrawTrend(Canvas drawingCanvas, ChartDataSegment Trend)
    {
        dynamic t = Trend as ChartDataSegment;
        if (t != null && t.Points != null) {
            for (int i = 1; i <= t.Points.Count - 1; i++) {
                dynamic toDraw = new Line {
                    X1 = t.Points(i - 1).X,
                    Y1 = t.Points(i - 1).Y,
                    X2 = t.Points(i).X,
                    Y2 = t.Points(i).Y,
                    StrokeThickness = 2,
                    Stroke = t.LineColor
                };
                drawingCanvas.Children.Add(toDraw);
            }
        }
    }

}

public class ChartDataSegment : DependencyObject
{


    public static readonly DependencyProperty _LineColor = DependencyProperty.Register("LineColor", typeof(Brush), typeof(ChartDataSegment), new PropertyMetadata(null));
    public Brush LineColor {
        get { return (Brush)GetValue(_LineColor); }
        set { SetValue(_LineColor, value); }
    }

    public static readonly DependencyProperty _LineThickness = DependencyProperty.Register("LineThickness", typeof(Thickness), typeof(ChartDataSegment), new PropertyMetadata(null));
    public Thickness PointThickness {
        get { return (Thickness)GetValue(_LineThickness); }
        set { SetValue(_LineThickness, value); }
    }

    public static readonly DependencyProperty _Points = DependencyProperty.Register("Points", typeof(ObservableCollection<Point>), typeof(ChartDataSegment), new UIPropertyMetadata(null));
    public ObservableCollection<Point> Points {
        get { return (ObservableCollection<Point>)GetValue(_Points); }
        set { SetValue(_Points, value); }
    }
}
var lineTrend1 = new ChartDataSegment {
    LineColor = Brushes.Blue,
    Points = new ObservableCollection<Point>({
        new Point {
            X = 1,
            Y = 1
        },
        new Point {
            X = 50,
            Y = 20
        },
        new Point {
            X = 100,
            Y = 100
        },
        new Point {
            X = 150,
            Y = 130
        }
    })
};

var ctrl = new LineGraph();
ctrl.Trends.Add(lineTrend1);
<WpfCharts:SpiderChart Title="Spider chart"  
                   Lines="{Binding Lines}" 
                   Axis="{Binding Axes}" 
                   Minimum="0" 
                   Maximum="1" 
                   Ticks="5" 
                   ShowLegend="True" 
                   LegendLocation="BottomRight" 
                   LegendBackgroundColor="Aquamarine"/>