3

I'm actually trying to add in a asynchronous way some UIElement to my Canvas define in my MainPage.

As I understand the basic way to add UIElement to a Canvas is to add it on his UIElementCollection, for example with a Line I should do like that:

        Line line = new Line();

        // Line attributes
        line.Stroke = new SolidColorBrush(Colors.Purple);
        line.StrokeThickness = 15;
        Point point1 = new Point();
        point1.X = 0;
        point1.Y = 0;
        Point point2 = new Point();
        point2.X = 480;
        point2.Y = 720;
        line.X1 = point1.X;
        line.Y1 = point1.Y;
        line.X2 = point2.X;
        line.Y2 = point2.Y;
        // Line attributes

        MyCanvas.Children.Add(line);

Let's imagine that I have a Class call Graphics that needs to access this Canvas in order to draw on it.

 public class Graphics
 {
     public void drawLine()
     {
            //Using Dispatcher in order to access the main UI thread
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
               Line line = new Line();

               // Line attributes

               /**
                *  Here I want to access the Canvas of the MainPage
                *  I have no Idea what to put here !!!
                *
                **/

            });
      }
  }

In the place "I have no Idea what to put here !!!" I tried to access directly to the MainPage Canvas --> FAIL

I tried to declare a public static UIElementCollection in the MainPage in order ta add my UIElement then pass it to the Canvas but not possible because UIElementCollection has no constructor --> FAIL

But those ideas seems to be dirty coding and not really elegant. So through my research I see that MVVM should do the magic. But all the tutorial I found were doing the data-biding through the xaml file which can't be use in my case.

So I have 2 questions:

First: How is use the UIElementCollection of the Canvas? (is there a hidden method called who draws it, like Paint or Repaint in JAVA?)

Second: If I want to follow the MVVM pattern can I consider the MainPage as my View, the Graphics class as my ViewModel and the UIElement as my Model?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Yann
  • 71
  • 8

1 Answers1

1

This is a really basic example but should get you going in the correct direction.

Graphics.cs

 public class Graphics
{
    public ObservableCollection<UIElement> UIElements { get; set; }
    int poisiton = 0;
    private Timer backgroundTimer;
    public Graphics()
    {
        this.UIElements = new ObservableCollection<UIElement>();
        this.backgroundTimer = new Timer(new TimerCallback((timer) => {
            Deployment.Current.Dispatcher.BeginInvoke(() => this.GenerateLine());
        }), null, 2000, 3000);
    }

    private void GenerateLine()
    {
        Line line = new Line();

        // Line attributes
        line.Stroke = new SolidColorBrush(Colors.Purple);
        line.StrokeThickness = 15;
        Point point1 = new Point();
        point1.X = this.poisiton;
        point1.Y = this.poisiton;
        Point point2 = new Point();
        point2.X = this.poisiton;
        point2.Y = this.poisiton + 30;
        line.X1 = point1.X;
        line.Y1 = point1.Y;
        line.X2 = point2.X;
        line.Y2 = point2.Y;
        // Line attributes

        this.poisiton += 10;
        UIElements.Add(line);
    }
}

MainPage.xaml.cs

 public MainPage()
 {
      InitializeComponent();

      this.Loaded += MainPage_Loaded;
      // Sample code to localize the ApplicationBar
      //BuildLocalizedApplicationBar();
 }

  void MainPage_Loaded(object sender, RoutedEventArgs e)
  {
      var graphics = new Graphics();
      this.ContentPanel.DataContext = graphics;
  }

MainPage.xaml

  <Canvas x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
      <ItemsControl ItemsSource="{Binding UIElements}">

      </ItemsControl>
  </Canvas>

I hope this helps.

Blounty
  • 3,342
  • 22
  • 21
  • Thank you a lot for your help ! Do you have an idea how to do it asynchronously ? Because in that case I can only do it in the constructor. – Yann Jul 16 '13 at 10:51
  • Can you give me some more info on how you want it to be asynchronous? What calls the adding of an element? etc – Blounty Jul 16 '13 at 11:12
  • Let's says that another thread is running. This thread could want to use GenerateLines(), in that case some Line Object will be added into UIElements observable collection. I would like to do something like in the MVVM pattern. It means I would like an event to be raise in order to add those Line on the screen but unfortunately UIElement class doesn't implement INotifyProperty so I don't know how to raise the event and I don't know aswell how to make my MainPage listen to those events in order to repaint. Thank you for your help and your time ! – Yann Jul 17 '13 at 02:27
  • I have updated my sample to handle something that matches your use case. You basically have to make sure that the UIElement is created on the main thread. I have tested the above and it works fine. Hope it helps. – Blounty Jul 17 '13 at 06:52
  • There still one point I don't understand, in our case the "draw" method (if there is one) is called when the MainPage loads. I try to draw things on the Canvas outside the MainPage initialization process but how can I do this ? I mean, is there something like a listener inside the MainPage that could call the "draw" method like in the observer pattern ? That basically what I mean by asynchronous. Thank you again this still helps me a lot! – Yann Jul 17 '13 at 09:26
  • I guess doing it the way i have described you can have any methods you require on the Graphics class and call the from wherever you like. I am struggling to understand the context of what you are trying to do im afraid. Could you give me an example? – Blounty Jul 17 '13 at 09:38
  • 1
    I finally manage to do what I wanted to do. My thread was creating another instance of the class Graphics (so 2 instances, one in the MainPage wich was binded through DataContext and one in another class), and this new instance wasn't bind to the Canvas. Thank you a lot for your help and your time even if I was not easy to understand ;) – Yann Jul 18 '13 at 06:47