Problem z dynamicznym tworzeniem komponentów

0

Witam. Mam problem z dynamicznym stworzeniem dowolnej kontrolki. Otóż przykładowo chciałbym stworzyć przycisk i nadać mu podstawowe parametry. W tym celu w zdarzeniu on-click innego przycisku (przeciągniętego z toolboxa) umieściłem następujący kod:

            Button btn1 = new Button();
            btn1.Width = 300;
            btn1.Height = 100;
            btn1.Content = "NOWY BUTTON";

            btn1.HorizontalAlignment = HorizontalAlignment.Left;
            btn1.VerticalAlignment = VerticalAlignment.Top;

            Thickness tmp_margin = btn1.Margin;
            tmp_margin.Left = 200;
            tmp_margin.Top = 200;
            btn1.Margin = tmp_margin;

Niestety przycisk nie pojawia się na formie, mimo że został stworzony (wnioskuję po tym że mogę się odwoływać do jego parametrów).

0

Jest utworzony, ale musisz go jeszcze dodać do formy. Dopisz sobie na końcu:
this.Controls.Add(btn1);

0

Zrobiłem jak mówisz i pojawił się następujący błąd:
*[CS1061] 'MainWindow' does not contain a definition for 'Controls' and no extension method 'Controls' accepting a first argument of type 'MainWindow' could be found (are you missing a using directive or an assembly reference?)
*

1

Button btn1 = new Button();

Button to tylko Button. Skąd ma wiedzieć na którym oknie ma się pojawić?
Controls.Add to jest w WinForms. w WPF musiałbyś dodać kontrolkę jako Content innej, albo np. do grida przez Children.Add.

0
Azarien napisał(a):

Button btn1 = new Button();

Button to tylko Button. Skąd ma wiedzieć na którym oknie ma się pojawić?
Controls.Add to jest w WinForms. w WPF musiałbyś dodać kontrolkę jako Content innej, albo np. do grida przez Children.Add.

Sorry:). Nie zauważyłem, że to WPF. Pewnie jeszcze najpierw trzeba jakoś nazwać tego grida bo standardowo chyba jej nie posiada w xaml i potem zastosować do tej nazwy Children.Add.

2

W xaml dodaj sobie nazwę grida lub innego elementu, w który chcesz wstawić button, np(dla grida):
<Grid x:Name="gridek">...

Potem do swojego kodu dodaj na końcu:
gridek.Children.Add(btn1);

0

Sposób z gridem działa. Ale teraz nie potrafię się odwołać do stworzonego w ten sposób obiektu w innym miejscu w kodzie niż tam gdzie został utworzony.
Przykładowo mam 2 przyciski statyczne. W jednym kod tworzący dynamicznie nowy przycisk. A w tamtym drugim kod zmieniający Content tego nowoutworzonego:

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Button btn1 = new Button();
            btn1.Width = 60;
            btn1.Height = 20;
            btn1.Content = "button 111";
            grid1.Children.Add(btn1);
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
           grid1.btn1.Content = "button 222";       //<--- NIE DZIAŁA
        }
1

Spróbuj tego:


        Button btn1;
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            btn1 = new Button();
            btn1.Width = 60;
            btn1.Height = 20;
            btn1.Content = "button 111";
            grid1.Children.Add(btn1);
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
           btn1 .Content = "button 222";   
        }
1

Nie odwołuj się do btn2, ale do ostatnio dodanego child (button) dla grid1:
var grid1LastChild = (Button)grid1.Children[grid1.Children.Count - 1];
grid1LastChild.Content = "Wacek";

0

@cSharpKazik: Spróbowałem, program się kompiluje ale kliknięcie button2 zawiesza program i wyrzuca komunikat: title
@wielki Kot1: Działa. Z tym że chciałbym dodać na jednego grida wiele obiektów (co mi się udało). Wówczas istnieje możliwość by odwołać się nie tylko do ostatnio dodanego ale też do pozostałych?

2

@Erwin14: masz błąd, bo nie użyłeś kodu, który podał Ci @cSharpKazik tylko swój własny. W button1_Click tworzysz nową zmienną Button btn1 = new Button(); zamiast operować na polu klasy: btn1 = new Button();.
Czytaj uważnie i pisz uważnie.

0

@somekind Rzeczywiście, nie zwróciłem na to uwagi.
@cSharpKazik A więc okazało się że twój kod w pełni rozwiązuje mój problem.

0

Pojawił mi się jeszcze kolejny problem. Otóż chciałbym zrobić klasę, której stworzenie instancji tworzy przycisk.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace WpfApplication2
{
    class MojPrzycisk
    {
        int wysokosc;
        int szerokosc;
        string nazwa;
        Button btn1;

        MojPrzycisk(int wysokosc, int szerokosc, string nazwa)
        {
            this.wysokosc = wysokosc;
            this.szerokosc = szerokosc;
            this.nazwa = nazwa;

            btn1 = new Button();
            btn1.Width = szerokosc;
            btn1.Height = wysokosc;
            btn1.Content = nazwa;
            MainWindow.grid1.Children.Add(btn1); //<--Tutaj zwraca błąd. Dodałem "MainWindow." bo bez niego program nie wie co to grid1. Spowodowało to kolejny błąd opisany pod kodem.
        }
    }
}

Niestety próba kompilacji kończy się błędem [CS0120] An object reference is required for the non-static field, method, or property.

1

Nie wiem czy Cie dobrze rozumiem, ale jeżeli tak to spróbuj przekazać grida w konstruktorze.

np.

MojPrzycisk(int wysokosc, int szerokosc, string nazwa, DataGrid grid)
{
    //...
   grid.Children.Add(btn1);

}

i tak to możesz wywoływać:

var mojPrzycisk = new MojPrzycisk(100, 100, "MojPrzycisk", grid1);
0

Działa. Zmieniłem tylko "DataGrid" na "Grid" w nagłówku konstruktora.

W jaki sposób mogę przypisać zdarzenie on-click do powstałego w ten sposób buttona?

1

Standardowo tak jak się tworzy zdarzenia, np:

btn.Click += Btn_Click;
0

Działa. Dziękuję wszystkim za odpowiedzi.
Dla przyszłych osób które to będą czytać dodam że zauważyłem że nie ma potrzeby tworzyć nowego grida. Wystarczy domyślnemu gridowi który się tworzy automatycznie i zawiera wszystkie komponenty przypisać nazwę w xaml i do niej się odwoływać.
title

1 użytkowników online, w tym zalogowanych: 0, gości: 1