Risipa de key_press | Programare

Programare .Net | Tehnici de programare | Tutoriale | Lectii si exemple

Risipa de key_press | Programare - Programare .Net | Tehnici de programare | Tutoriale | Lectii si exemple

WPF – utilizarea c# pentru UI

Pana acum am folosit XAML pentru a construi fereastra aplicatiei. Toate controalele au fost create cu ajutorul XAML, c# fiind folosit numai pentru diverse operatii logice. In continuare imi propun sa construiesc o aplicatie WPF fara a folosi XAML. Mai exact, in afara de fereastra propriu-zisa, tot continutul va fi cnstruit folosind numai c#.

Pentru asta voi crea un proiect nou, pe care il voi numi… FaraXaml. Din Solution Explorer voi deschide fisierul MainWindow.xaml.cs – fisier care contine numai urmatorul cod:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Conatainers
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}


Vom completa constructorul pentru a “construi” fereastra aplicatiei. Vreau sa construiesc o aplicatie (fereastra) care sa contina un Border, in intriorul conturului va fi un DockPanel care va contine 2 elemente: un StackPanel si un Grid cu 2 coloane si 2 randuri. In StackPanel vor fi cateva controale care imi vor permite sa adaug in Grid Shapes, specificand celula in care sa fie adaugate si forma.

Pentru inceput voi desena un contur (Border):

namespace Conatainers
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Content = null;
            AddContent();
        }

        public void AddContent()
        {
            Border b = new Border();  //un nou contur
            b.BorderThickness = new Thickness(3);  //grosimea liniei
            b.BorderBrush = new SolidColorBrush(Colors.DarkCyan);  //culoarea liniei

            /* Alte controale */

            this.AddChild(b);
        }
    }
}

Din acest moment nu voi mai posta tot cedul din fisierul cs, ci doar metoda AddContent() si eventualele metode ajutatoare pe care le voi folosi.

Dupa ce am adaugat codul anterior, fereastra arata asa:

Se observa conturul de coloare DarkCyan care delimiteaza suprafata de lucru a ferestrei.

        public void AddContent()
        {
            Border b = new Border();  //un nou contur
            b.BorderThickness = new Thickness(3);  //grosimea liniei
            b.BorderBrush = new SolidColorBrush(Colors.DarkCyan);  //culoarea liniei

            DockPanel dp = new DockPanel();
            dp.Background = new SolidColorBrush(Colors.AliceBlue);
            
            StackPanel sp = new StackPanel();
            sp.Background = new SolidColorBrush(Colors.Salmon);
            sp.SetValue(DockPanel.DockProperty, Dock.Top);  //se seteaza proprietatea Dock, de tip DependencyProperty
            sp.Height = 25;

            Grid grid = new Grid();
            grid.Background = new SolidColorBrush(Colors.AntiqueWhite);


            dp.Children.Add(sp);  //elementul dockPanel primeste un elemetn copil: StackPanel
            dp.Children.Add(grid);  //elementul dockPanel primeste un elemetn copil: Grid
            b.Child = dp;  //conturului i se stabileste elementul copil
            this.AddChild(b);
        }

Fara a intra in detalii, vreau sa evidentiez urmatoarea linie:

sp.SetValue(DockPanel.DockProperty, Dock.Top);  //se seteaza proprietatea Dock, de tip DependencyProperty

In aceasta linie este setata properietatea Dock a StackPanel-ului. Aceasta proprietate este de tipul DependencyProperty. Despre asta voi scrie un capitol intreg in curand. Foarte multe controale au astfel de proprietati, nou introduse in WPF. Pentru a seta o astfel de proprietate se foloseste metoda SetValue, care primeste ca prim parametru DependencyProperty care trebuie stabilita si ca al doilea parametru valoarea (obiect) propriu-zisa. Detalii despre acest tip in curand.
Am colorat fiecare element adaugat in culori diferite pentru a fi usoara identificare vizuala. In aplicatia finala voi anula aceste culori.

Acum fereastra arata asa:

Am continuat construirea ferestrei si am ajuns la urmatoarea etapa:

        public void AddContent()
        {
            Border b = new Border();  //un nou contur
            b.BorderThickness = new Thickness(3);  //grosimea liniei
            b.BorderBrush = new SolidColorBrush(Colors.DarkCyan);  //culoarea liniei

            DockPanel dp = new DockPanel();
            dp.Background = new SolidColorBrush(Colors.AliceBlue);
            
            StackPanel sp = new StackPanel();
            sp.Background = new SolidColorBrush(Colors.Salmon);
            sp.Orientation = Orientation.Horizontal;
            sp.SetValue(DockPanel.DockProperty, Dock.Top);  //se seteaza proprietatea Dock, de tip DependencyProperty
            sp.Height = 25;

            Grid grid = new Grid();
            grid.Background = new SolidColorBrush(Colors.AntiqueWhite);
            grid.RowDefinitions.Add(new RowDefinition());        //se definesc randurile
            grid.RowDefinitions.Add(new RowDefinition());
            grid.ColumnDefinitions.Add(new ColumnDefinition());  //si coloanele
            grid.ColumnDefinitions.Add(new ColumnDefinition());

            TextBlock tb_r = new TextBlock();
            tb_r.Text = "Row";
            tb_r.Margin = new Thickness(5, 0, 3, 0);
            TextBlock tb_c = new TextBlock();
            tb_c.Text = "Col";
            tb_c.Margin = new Thickness(5, 0, 3, 0);  //am definit textul
            tb_c.VerticalAlignment = tb_r.VerticalAlignment = System.Windows.VerticalAlignment.Center;


            ComboBox cb_r = new ComboBox();
            ComboBox cb_c = new ComboBox();
            cb_c.Width = cb_r.Width = 40;
            for (int i = 0; i < grid.RowDefinitions.Count; i++)
                cb_r.Items.Add(new ComboBoxItem().Content = i);
            for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
                cb_c.Items.Add(new ComboBoxItem().Content = i);

            TextBlock tb_shape = new TextBlock();
            tb_shape.VerticalAlignment = System.Windows.VerticalAlignment.Center;
            tb_shape.Text = "Shape";
            tb_shape.Margin = new Thickness(5, 0, 3, 0);

            ComboBox cb_shapes = new ComboBox();
            cb_shapes.Width = 90;
            cb_shapes.Items.Add(new ComboBoxItem().Content = "Cerc");
            cb_shapes.Items.Add(new ComboBoxItem().Content = "Patrat");

            Button btnAdd = new Button();
            btnAdd.Content = "Add";
            btnAdd.Click += new RoutedEventHandler(btnAdd_Click);

            sp.Children.Add(tb_r);
            sp.Children.Add(cb_r);
            sp.Children.Add(tb_c);
            sp.Children.Add(cb_c);
            sp.Children.Add(tb_shape);
            sp.Children.Add(cb_shapes);
            sp.Children.Add(btnAdd);



            // Panoul de comanda:


            dp.Children.Add(sp);  //elementul dockPanel primeste un elemetn copil: StackPanel
            dp.Children.Add(grid);  //elementul dockPanel primeste un elemetn copil: Grid
            b.Child = dp;  //conturului i se stabileste elementul copil
            this.AddChild(b);
        }

        void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            //throw new NotImplementedException();
        }

care arata asa:

Acum avem urmatoarele elemente: 3 ComboBox, 3 TextBlock si un Buton. Cu ajutorul ComboBox-urilr se poate alege locul in grid unde se doreste amplasarea unei forme geometrice, horma care este desenata la apasarea butonului. Dupa cum se poate vede in cod, am construit continutul celor doua ComboBox-uri care se ocupa de pozitionare dinamic, in functie de numarul de coloane si randuri din grid, astfel incat, in momentul in care voi modifica dimensiunea Grid-ului aceste valori sa se adapteze.
In cod a aparut o noua metoda pentru tratarea evenimentului Click pe Buton. Tot ce imi mai ramane de facut acum e sa scriu codul care se va ocupa cu desenarea formelor geometrice. Pentru a-mi fi mai usor, voi scoate, ca variabila globala, grid-ul in afara metodei unde este creat. Astfel voi avea tot timpul o referinta la el si nu va trebui sa il caut la fiecare apasare de buton in interiorul ferestrei. Acelasi lucru il voi aplica si celor 3 ComboBox-uri. Astfel imi va fi usor sa le citesc valoarea selectata de utilizator.

Am completat codul, acum aplicatia este aproape completa:

public partial class MainWindow : Window
    {
        Grid grid;
        ComboBox cb_r, cb_c, cb_shapes;
        double shapeW = 35;
        double shapeH = 35;
        Random rnd = new Random();

        public MainWindow()
        {
            InitializeComponent();
            this.Content = null;
            AddContent();
        }

        public void AddContent()
        {
            Border b = new Border();  //un nou contur
            b.BorderThickness = new Thickness(3);  //grosimea liniei
            b.BorderBrush = new SolidColorBrush(Colors.DarkCyan);  //culoarea liniei

            DockPanel dp = new DockPanel();
            dp.Background = new SolidColorBrush(Colors.AliceBlue);

            StackPanel sp = new StackPanel();
            sp.Background = new SolidColorBrush(Colors.Salmon);
            sp.Orientation = Orientation.Horizontal;
            sp.SetValue(DockPanel.DockProperty, Dock.Top);  //se seteaza proprietatea Dock, de tip DependencyProperty
            sp.Height = 25;

            grid = new Grid();
            grid.Background = new SolidColorBrush(Colors.AntiqueWhite);
            grid.RowDefinitions.Add(new RowDefinition());        //se definesc randurile
            grid.RowDefinitions.Add(new RowDefinition());
            grid.ColumnDefinitions.Add(new ColumnDefinition());  //si coloanele
            grid.ColumnDefinitions.Add(new ColumnDefinition());

            TextBlock tb_r = new TextBlock();
            tb_r.Text = "Row";
            tb_r.Margin = new Thickness(5, 0, 3, 0);
            TextBlock tb_c = new TextBlock();
            tb_c.Text = "Col";
            tb_c.Margin = new Thickness(5, 0, 3, 0);  //am definit textul
            tb_c.VerticalAlignment = tb_r.VerticalAlignment = System.Windows.VerticalAlignment.Center;


            cb_r = new ComboBox();
            cb_c = new ComboBox();
            cb_c.Width = cb_r.Width = 40;
            for (int i = 0; i < grid.RowDefinitions.Count; i++)
                cb_r.Items.Add(new ComboBoxItem().Content = i);
            for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
                cb_c.Items.Add(new ComboBoxItem().Content = i);

            TextBlock tb_shape = new TextBlock();
            tb_shape.VerticalAlignment = System.Windows.VerticalAlignment.Center;
            tb_shape.Text = "Shape";
            tb_shape.Margin = new Thickness(5, 0, 3, 0);

            cb_shapes = new ComboBox();
            cb_shapes.Width = 90;
            cb_shapes.Items.Add(new ComboBoxItem().Content = "Cerc");
            cb_shapes.Items.Add(new ComboBoxItem().Content = "Patrat");

            Button btnAdd = new Button();
            btnAdd.Content = "Add";
            btnAdd.Click += new RoutedEventHandler(btnAdd_Click);

            sp.Children.Add(tb_r);
            sp.Children.Add(cb_r);
            sp.Children.Add(tb_c);
            sp.Children.Add(cb_c);
            sp.Children.Add(tb_shape);
            sp.Children.Add(cb_shapes);
            sp.Children.Add(btnAdd);



            // Panoul de comanda:


            dp.Children.Add(sp);  //elementul dockPanel primeste un elemetn copil: StackPanel
            dp.Children.Add(grid);  //elementul dockPanel primeste un elemetn copil: Grid
            b.Child = dp;  //conturului i se stabileste elementul copil
            this.AddChild(b);
        }

        void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            if (cb_shapes.SelectedItem == null)
            {
                MessageBox.Show("Pentru a desena, selectati o forma geometrica.");
                return;
            }

            Shape s;
            //voi crea forma geometrica in functie de selectia utilizatorului
            if (cb_shapes.SelectedItem.ToString().ToLower() == "cerc")
                s = new Ellipse();
            else
                s = new Rectangle();

            s.Width = shapeW;
            s.Height = shapeH;
            s.Fill = new SolidColorBrush(Color.FromRgb((byte)rnd.Next(0, 256), (byte)rnd.Next(0, 256), (byte)rnd.Next(0, 256)));

            int row = cb_r.SelectedItem == null ? 0 : (int)cb_r.SelectedItem;
            int col = cb_c.SelectedItem == null ? 0 : (int)cb_c.SelectedItem;


            s.SetValue(Grid.ColumnProperty, col);
            s.SetValue(Grid.RowProperty, row);
            grid.Children.Add(s);
        }
    }

Si arata asa:

Ceea ce ma deranjeaza acum este ca la fiecare redesenare pe o pozitie ocupata, daca forma geometrica existenta este un patrat, si incerc sa desenez in aceeasi pozitie un cerc, patratul va fi vizibil sub cerc. Nu e frumos, si as vrea sa corectez asta. Voi scrie o metoda care sa se ocupe de aceasta misiune:

private void RemoveShape(int col, int row)
        {
            if (grid.Children == null)
                return;

            for (int i = 0; i < grid.Children.Count; i++)
            {
                UIElement elem = grid.Children[i];
                if ((int)elem.GetValue(Grid.ColumnProperty) == col && (int)elem.GetValue(Grid.RowProperty) == row)
                {
                    grid.Children.RemoveAt(i);
                    return;
                }
            }
        }

Aceasta metoda va fi apelata in btnAdd_Click inaine de a adauga noua forma geometrica in grid:

        void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            if (cb_shapes.SelectedItem == null)
            {
                MessageBox.Show("Pentru a desena, selectati o forma geometrica.");
                return;
            }

            Shape s;
            //voi crea forma geometrica in functie de selectia utilizatorului
            if (cb_shapes.SelectedItem.ToString().ToLower() == "cerc")
                s = new Ellipse();
            else
                s = new Rectangle();

            s.Width = shapeW;
            s.Height = shapeH;
            s.Fill = new SolidColorBrush(Color.FromRgb((byte)rnd.Next(0, 256), (byte)rnd.Next(0, 256), (byte)rnd.Next(0, 256)));  //o culoare random

            int row = cb_r.SelectedItem == null ? 0 : (int)cb_r.SelectedItem;
            int col = cb_c.SelectedItem == null ? 0 : (int)cb_c.SelectedItem;


            s.SetValue(Grid.ColumnProperty, col);
            s.SetValue(Grid.RowProperty, row);
            RemoveShape(col, row);
            grid.Children.Add(s);
        }

Asta e forma la care am vrut sa ajung. Bineinteles ca modul acesta de scriere nu e cel mai eficient, in XAML as fi scris mult mai repede si mai eficient totul. Ca un secret, pentru a scrie tot codul c# de mai sus am scris inainte totul in XAML deoarece e mai usor din punct de vedere al designului de construit totul in XAML si am luat element cu element si le-am “tradus” in c#. Ca tema pentru acest capitol: sa se (re)scrie codul aplicatiei de mai sus cu ajutorul XAML.

Cu ce ne vom ocupa in continuare? Voi scrie un capitol despre proprietatile cele mai utilizate ale controalelor din WPF.

Category: Uncategorized

Your email address will not be published. Required fields are marked *

*