简体   繁体   中英

Drawing and removing shapes in WPF

In GDI+/WinForms, I could do this in the Click() event and using the graphics Object:

AddPoint(p); //Add Point contains some code to make sure there is only 3 dots
foreach (Point p in PointList) {
    DrawRectangle(p);
}
Invalidate();

If I try something similar in WPF, it won't cleanup the dots I created (I'm guessing because of how WPF works). What this means is if I check to make sure there is only three dots at a time, and pop off the oldest point to make room for the new one, the rectangle drawn would be still there.

So the question is, how can I create something in WPF that allows me to

  • Draw a rectangle at a Point
  • Remove rectangles/points from a WPF canvas after there is more than 3

You're doing WPF the WinForms way. Don't do that. It's like writing VB code in C++. It can only end in tears.

To do this the WPF way, use databinding and a view model class to do the logic of "no more than 3 at a time." Then, for the UI, just bind to the PointList in your view model.

Here's what my XAML should look like. Notice I'm just using an ItemsControl and a Canvas, then binding the ItemsSource to PointList:

<Window x:Class="WpfTester.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <ItemsControl ItemsSource="{Binding Path=PointList}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Rectangle Fill="Red" Width="25" Height="25" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</Window>

Then we just need to create the PointList. We'll use the normal WPF means: a view model class to hold the point list:

class MainViewModel
{
    public MainViewModel()
    {
        PointList = new ObservableCollection<Point>();

        // Some example data:
        AddPoint(new Point(10, 10));
        AddPoint(new Point(200, 200));
        AddPoint(new Point(500, 500));
    }

    public ObservableCollection<Point> PointList { get; private set; }

    public void AddPoint(Point p)
    {
        // 3 at most, please!
        if (PointList.Count == 3)
        {
            PointList.RemoveAt(0);
        }
        PointList.Add(p);
    }
}

Piece of cheese, yeah? So the final part is just telling the XAML to load your view model. Inside the the code-behind for your XAML, set the DataContext to your view model:

// Inside MainWindow.xaml.cs
public MainWindow()
{
    InitializeComponent();

    // Add this line:
    this.DataContext = new MainViewModel();
}

Now that you've got that in place, you can add/remove rectangles anywhere in your code simply by calling viewModel.AddPoint or viewModel.PointList.Remove, and the UI will automatically update to reflect the changes.

I would use wpf data binding to bind the content of the canvas to a collection of rectangles you store elsewere. You need to learn databinding anyway if you want to do serious WPF development.

Edit: Of course you store just the Rectangles, the data binding should create a shape for each rectangle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM