【问题标题】:Draw the same line multiple times, without losing previous trails多次绘制同一条线,而不会丢失以前的轨迹
【发布时间】:2017-02-16 15:49:06
【问题描述】:

我正在用 C# 开发一个 WPF,我想多次绘制一条特定的线,不会丢失之前的轨迹。我有 10 buttons 在我的 Grid 里面,我按下一个时,我想画一条线。对于这条线,我使用 var redLine 并且每次按下按钮时,它都会收到一对特定的坐标。

我用这段代码画线:

public partial class MainWindow : Window {

    private Line redLine = new Line();
    SolidColorBrush redBrush = new SolidColorBrush(Colors.Red);

    public MainWindow()
    {
        redLine.StrokeThickness = 4;
        redLine.Stroke = redBrush;
    }

   private void button1_Click(object sender, RoutedEventArgs e) {
       redLine.X1 = 237; 
       redLine.Y1 = 382;
       redLine.X2 = 288;
       redLine.Y2 = 409;
       //draw the line
       MainGrid.Children.Add(redLine);
   }

   private void button2_Click(object sender, RoutedEventArgs e) {
       redLine.X1 = 130; 
       redLine.Y1 = 323;
       redLine.X2 = 238;
       redLine.Y2 = 690;
       //draw the line
       MainGrid.Children.Add(redLine);
   }
} 

但每次我按button1 然后按button2 时都会出现此错误(其他按钮也会出现此错误):

错误 指定的视觉对象已经是另一个视觉对象的子对象或某个对象的根 构图目标。

我确实想保留两条线,而不是为了绘制第二条而删除第一条。关于如何解决它的任何想法?

注意我不想在每个 buttonX_Click 方法中声明每一行(整个程序大约有 11 行)。

【问题讨论】:

  • “我不想在每个 buttonX_Click 方法中声明每一行(整个程序大约有 11 行)。” 为什么不呢?它可能会解决问题。是否纯粹是为了不必重复宽度/画笔等的实例化/设置?
  • 不应该是CheckBoxes 来显示/隐藏行吗?在 WPF 中,您可以使用数据模板来可视化项目集合(在您的案例中)。见this。只需将新项目添加到集合中,新行就会出现在视图中。
  • @JamesThorpe 我认为从编程方面一遍又一遍地声明每一行是“正确的”。
  • 我没有说这是最终解决方案,我只是想知道这是否是不重新声明它的原因。如果这的原因,那么还有其他方法,比如让每个按钮调用一个仅提供坐标的函数,并让该单个函数创建线,设置属性并添加它。
  • @Sinatr 我正在尝试创建类似于“图像映射”的东西。所以我不想要 CheckBox,因为它会一直显示,不像按钮。

标签: c# wpf visual-studio lines children


【解决方案1】:

错误信息很清楚,Line 已经是MainGrid 的子元素。不能再次添加。

在将其添加到 MainGrid 之前,您必须创建一个新的 Line

private void button1_Click(object sender, RoutedEventArgs e)
{
    var newLine = new Line
    {
       Stroke = redBrush,
       StrokeThickness = 4,
       X1 = 237,
       Y1 = 382,
       X2 = 288,
       Y2 = 409
    };
    MainGrid.Children.Add(newLine);
}

显然你也不再需要private Line redLine 成员了。

【讨论】:

  • 我知道它是 MainGrid 的一个子元素。但我希望避免每次都创建一个新行(正如我提到的,10 个按钮中有 11 行被多次使用。我还能做些什么吗?
  • 您不能将单个 Line 元素添加到任何父控件两次。然而,还有其他方法可以在 WPF 中“绘制”事物。从这里开始阅读:Shapes and Basic Drawing in WPF Overview.
【解决方案2】:

我建议遵循此示例的方法 (MVVM)。它通过单击按钮随机添加新行。

主窗口

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModelLine();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ViewModelLine vm = (ViewModelLine)DataContext;

        // use other information and decide how you want to add the line
        Random ran = new Random();
        vm.Models.Add(new ModelLine() { X1=ran.Next(1,600), X2= ran.Next(1, 600), Y1= ran.Next(1, 600), Y2= ran.Next(1, 600) });
    }
}

查看

<DockPanel >
    <Button Content="Add a New Line" DockPanel.Dock="Top" Click="Button_Click"/>
    <ItemsControl DockPanel.Dock="Bottom" DataContext="{Binding}" ItemsSource="{Binding Models}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Line X1="{Binding X1}" X2="{Binding X2}" Y1="{Binding Y1}" Y2="{Binding Y2}" 
                      Stroke="Black" StrokeThickness="2"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</DockPanel> 

查看模型

public class ViewModelLine
{
    public ViewModelLine()
    {
        _models = new ObservableCollection<ModelLine>(); 
    }
    ObservableCollection<ModelLine> _models;
    public ObservableCollection<ModelLine> Models { get { return _models; } set { _models = value; } }

}

型号

public class ModelLine : INotifyPropertyChanged
{ 
    int _x1;
    public int X1 { get { return _x1; } set { _x1 = value; RaisePropertyChanged("X1"); } }

    int _x2;
    public int X2 { get { return _x2; } set { _x2 = value; RaisePropertyChanged("X2"); } }

    int _y1;
    public int Y1 { get { return _y1; } set { _y1 = value; RaisePropertyChanged("Y1"); } }

    int _y2;
    public int Y2 { get { return _y2; } set { _y2 = value; RaisePropertyChanged("Y2"); } }

    public event PropertyChangedEventHandler PropertyChanged;
    void RaisePropertyChanged(string propname)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
    }
}

请注意,ModelLine 可以包含其他属性,例如 Stroke 和 Thickness。

【讨论】:

  • 感谢您的努力和时间。我将在每个单独的 buttonX_click 方法中声明每一行
猜你喜欢
  • 2015-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多