How to get numbers in different positions

I want to get only one number and one circle when I click the button so if I click the button 3 times I will get the 3 numbers with the circles obviously. It's suppose to be lottery numbers appearing after every click but I have no idea how can I do that.

    private void btnGo_Click(object sender, RoutedEventArgs e)
    {
        Ellipse first = new Ellipse();
        first.Fill = new SolidColorBrush(Colors.Red);
        first.Height = 70;
        first.Width = 70;
        first.Margin = new Thickness(50, 100, 0, 0);
        caPaper.Children.Add(first);

        Ellipse second = new Ellipse();
        second.Fill = new SolidColorBrush(Colors.Red);
        second.Height = 70;
        second.Width = 70;
        second.Margin = new Thickness(150, 100, 0, 0);
        caPaper.Children.Add(second);

        Ellipse third = new Ellipse();
        third.Fill = new SolidColorBrush(Colors.Red);
        third.Height = 70;
        third.Width = 70;
        third.Margin = new Thickness(250, 100, 0, 0);
        caPaper.Children.Add(third);

        Random rd = new Random();

        TextBlock txt1 = new TextBlock();
        txt1.FontSize = 20;
        txt1.Foreground = Brushes.White;
        txt1.Text = " " + rd.Next(1, 45);
        Canvas.SetTop(txt1, 120);
        Canvas.SetLeft(txt1, 70);
        caPaper.Children.Add(txt1);

        TextBlock txt2 = new TextBlock();
        txt2.FontSize = 20;
        txt2.Foreground = Brushes.White;
        txt2.Text = " " + rd.Next(1, 45);
        Canvas.SetTop(txt2, 120);
        Canvas.SetLeft(txt2, 170);
        caPaper.Children.Add(txt2);

        TextBlock txt3 = new TextBlock();
        txt3.FontSize = 20;
        txt3.Foreground = Brushes.White;
        txt3.Text = " " + rd.Next(1, 45);
        Canvas.SetTop(txt3, 120);
        Canvas.SetLeft(txt3, 270);
        caPaper.Children.Add(txt3);

    }

    private void btnClear_Click(object sender, RoutedEventArgs e)
    {
        caPaper.Children.Clear();

2 answers

  • answered 2018-10-09 16:41 Cory

    As mentioned below, your approach could use a bit of tweaking. WPF has some really powerful data binding features to build UI MUCH MORE pain free. However to answer your question...

    It looks as though the only thing that is 'unique' per ball is the margin of the ball and the left value in Canvas.SetLeft

    You should be able to derive those values based on the number of children in your canvas. For example something like this:

    int marginLeft = 50 + (caPaper.Children.Length * 100);
    
    Ellipse newBall = new Ellipse();
    newBall.Fill = new SolidColorBrush(Colors.Red);
    newBall.Height = 70;
    newBall.Width = 70;
    newBall.Margin = new Thickness(marginLeft, 100, 0, 0);
    caPaper.Children.Add(newBall);
    

    You'll want to adjust that of course but I wanted to give you an idea to work with. Also, the same will need to be done for the text. Then, each time you click it, it will create them in relation to the number of children it already has.

  • answered 2018-10-09 17:16 BradleyDotNET

    This is 100% the wrong approach to this.

    You should never be dynamically creating UI controls like this. It's so wrong its not worth figuring out what is wrong in your code.

    Use MVVM, it will make your life much, much, much easier. Your lottery numbers are data, the balls, a visual representation of that data. So in your VM:

    public ObservableCollection<int> Draws {get;} = new ObservableCollection<int>();
    
    // Invoked from command, or could be a click handler until you learn commands
    public AddDraw()
    {
         int draw = GetNextDraw(); //Left as an exercise
         Draws.Add(draw)
    }
    

    Now that the data is handled, we need to display it. An ItemsControl is how you display collections, use the ItemTemplate to control how the number is displayed (the ball) and ItemsPanel to control the layout (a horizontal WrapPanel is probably what you want):

    <ItemsControl ItemsSource="{Binding Draws}">
       <ItemsControl.ItemTemplate>
           <DataTemplate>
              <Grid>
                 <Ellipse Fill="Red/>
                 <TextBlock Text="{Binding Path=.}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
              </Grid>
           </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
           <ItemPanelTemplate>
              <WrapPanel Orientation="Horizontal"/>
           </ItemPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
    

    That's off the top of my head so I may have a property or class wrong. Intellisense should correct it pretty quickly though.

    Once its set up you can add margin, change the colors, whatever. This design is what WPF was built for, take advantage of it.

    Disclaimer: I have had to deal with creating UI controls at all ONCE. In 7 years of professional WPF work, and only because the data structure being represented was incredibly complex (and not similar to how it was being represented).