WPF, zdarzenia a funkcje anonimowe

WPF, zdarzenia a funkcje anonimowe
T9
  • Rejestracja:około 10 lat
  • Ostatnio:około 6 lat
  • Postów:329
0

Chciałem program który generował bym kod grafu, na podstawie rysunku zrobionego przez użytkownika. Program ma kilka stanów, dodawanie, rysowanie , oczekiwanie itd. Chciałem zamiast kilku metod w stylu lewy_klik_w_tło, prawy_kilk.. i tysiąca if'ów w każdej, mieć dużo malutkich metod i podmieniać je wraz ze zmianą stanu . Taki był plan... Kod w wersji v1 działa tak że nie ważne co będzie się działo ze zmienną _vertexClickHandler, choćby tam null był, to wykona się funkcja przechowywana przez _vertexClickHandler; w momencie internalizacji. Wersja z lambdą działa "normalnie" tylko nie mam pojęcia o co właciwie chodzi :? wytłumaczył by ktoś ta magie?

Kopiuj
 
        private Action<object, MouseEventArgs> _vertexClickHandler;
        private void AddVertex(object sender, MouseEventArgs e)
        {
         // v1-nie działa
         // Vertex v = new Vertex( _vertexClickHandler));
         //v2 działa
           Vertex v = new Vertex( (x, y) => { _vertexClickHandler(x, y); }); 

           var pos = e.GetPosition(this.VertexLayer);
           v.Draw(pos.X, pos.Y);
        }
class Vertex()
{//(...)
        public Vertex( Action<object, MouseEventArgs> clickHandler)
        {
            this.Click = clickHandler;
            this._tb = new TextBox();
            this._body = new Ellipse();
            this._tb.PreviewMouseDown += SendClickToComposite;
            this._body.PreviewMouseDown += SendClickToComposite;
        }
        private void SendClickToComposite(object o, MouseEventArgs e)
        {
            this.Click(this, e);
        }
}
edytowany 2x, ostatnio: topik92
T9
  • Rejestracja:około 10 lat
  • Ostatnio:około 6 lat
  • Postów:329
0

Na mój rozum Action to tylko ładnie zapisany wskaźnik do funkcji, a nie żaden obiekt i używając referencji do akcji tak na prawdę posługujemy się referencją do tej funkcji. Taki cukierek składniowy.. Znak ktoś jakieś źródła gdzie jest dokładnie wyśnione jak to działa?.

Kopiuj
        public static Action _method=m1;
        static void Main(string[] args)
        {
            MyClass c1 = new MyClass(_method);
            MyClass c2 = new MyClass(() => { _method(); });
            MyClass c3 = new MyClass(new Action(() => { _method(); }));  
            MyClass2 sdClass = new MyClass2(_method);
            Console.WriteLine("Próba kontorlna");
            _method();
            c1.actn();
            c2.actn();
            c3.actn();
            sdClass.actn();
 // wynik :
//metoda 1
//metoda 1
//metoda 1
//metoda 1
//metoda 1
            _method = m2;
            Console.WriteLine("Zamina metody");
            _method();
            c1.actn();
            c2.actn();
            c3.actn();
            sdClass.actn();
 // wynik :
//metoda 2
//metoda 1
//metoda 2
//metoda 2
//metoda 1
            Console.ReadKey();
        }
        class MyClass
        {
            public Action actn { get; set; }
            public MyClass(Action action)
            {
                this.actn = action;
            }
        }
        class MyClass2
        {
            public Action actn { get; set; }
            public MyClass2(Action action)
            {
                this.actn = new Action(action);
            }
        }
        static void m1()
        {
            Console.WriteLine("metoda 1");
        }
        static void m2()
        {
            Console.WriteLine("metoda 2");;
        }
 
edytowany 2x, ostatnio: topik92
katelx
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Hong Kong
2

najprawdopodobniej chodzi ci o wyjasnienie jak dzialaja closures w c#, z tego co pamietam w c# in depth bylo to opisane w dosc prosty a zarazem wyczerpujacy sposob.
w sytuacji jesli w lambdzie (lub anonimowym delegacie) bedzie uzywana zmienna A ktora jest zdefiniowana w zewnetrznym zakresie to w chwili wywolania tejze lambdy, bedzie uzyty stan zmiennej A z momentu w ktorym lambda jest wywolywana a nie w ktorej byla definiowana, przykladowo:

Kopiuj
var number = 1;
var write = new Action(() => Console.WriteLine(number));
number++;
write();//wypisuje 2

co sie dzieje pod spodem? kompilator dla twojej lambdy generuje dodatkowa strukture ktora trzyma referencje do 'przechwyconych' obiektow.
btw ten cukier skladniowy o ktorym mowisz to nie jest na wskazniki do funkcji a na 'pelnowartosciowe' obiekty, zwane delegatami (instancje klasy MulticastDelegate) ktore oprocz trzymania referencji do funkcji (niekoniecznie jednej) maja calkiem spora game utilsow https://msdn.microsoft.com/en-us/library/system.multicastdelegate(v=vs.110).aspx

T9
Z tymi wskaźnikami to próbowałem sobie jakoś wyjaśnić dlaczego jest jak jest, z nadzieją ze jak trafie to ktoś potwierdzi, jak palne straszne głupoty to mniej lub bardziej dobitnie miej z błędu wyprowadzi i przynajmniej się dowiem:P.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.