Autor Beitrag
mannyk
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 83
Erhaltene Danke: 1



BeitragVerfasst: Do 10.02.11 13:18 
Hi Leute,

ich wollte mal fragen, wie man obigen Sachverhalt elegant modellieren könnte.

Bsp:
Ich entwickle gerade einen MP3 Player, welcher in verschiedene Schichten aufgeteilt ist.
Bis jetzt gibt es drei Schichten:

Präsentationsschicht (Gui)
Applikationsschicht
Domänenschicht

In der Domänenschicht (dort ist zb. das ganze Player-Management) gibt es oftmals events, die Nachrichten an die GUI schicken sollen (z.b. der Fortschritt eines Tracks, welcher mit einem Slider angezeigt werden soll).

Nun wollte ich fragen, wie solche Nachrichten oder Events elegeant modelliert werden können (ohne z.b. eine zu große Kopplung der Schichten zu verursachen). Folgend meine "Lösung", welche zwar funktioniert, ich bin aber nicht sicher ob die wirklich okay ist. Zusammenfasssend benutze ich Technologien wie Delegates und das Observer-Pattern. Was mich stört ist, das bei diesem Ansatz eine Schicht schlichtweg übersprungen wird.

Gui-Klasse (Auszug) des WPF-Formulars (Präsentationsschicht):
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
    public partial class Window1 : Window, IAudioPositionRegistrant
    {
        public Window1()
        {
            InitializeComponent();
            PlaybackManager.Instance.Register(this);
        }

        public delegate void SetSliderCallback(double percent);

        [...]      

        public void SetSlider(double percent)
        {
            slider1.Value = percent;
        }

        public void Notify(double percent)
        {
            SetSliderCallback callback = SetSlider;
            this.Dispatcher.Invoke(callback, new object[] { percent });
        }
    }


Interface IAudioPositionRegistrant
ausblenden C#-Quelltext
1:
2:
3:
4:
    public interface IAudioPositionRegistrant
    {
        void Notify(double percent);
    }


PlaybackManager-Klasse (Auszug) (Domänenschicht)
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
    public class PlaybackManager
    {
        private IAudioPositionRegistrant Registrant { get; set; }

        [...]

        public void Register(IAudioPositionRegistrant r)
        {
            Registrant = r;
        }

        void SongTracker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = (BackgroundWorker)sender;

            while (!worker.CancellationPending)
            {
                double percent = Audio.CurrentPosition * 100 / Audio.Duration;
                Registrant.Notify(percent);
                Thread.Sleep(500);
            }
        }
    }


Danke für eure Hilfe!
Lg,
mannyk


Moderiert von user profile iconKha: Topic aus C# - Die Sprache verschoben am Do 10.02.2011 um 14:30
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 10.02.11 15:28 
Allgemein machst du dir das Leben imo zu schwer: Wozu ein Observer-Pattern, wenn C# Events kennt? Noch einmal interessant wird das Pattern höchstens in Verbindung mit Dependency Injection.
Und speziell machst du dir das Leben zu schwer, indem du WPF aber nicht MVVM benutzt ;) .

_________________
>λ=
mannyk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 83
Erhaltene Danke: 1



BeitragVerfasst: Fr 11.02.11 09:45 
Hallo und danke für deine Tipps!
Ich habe nun deinen Rat berherzigt und das Ergebnis gefällt mir dementsprechend auch viel besser. Hier die neue Version:

Gui-Klasse (Auszug) des WPF-Formulars (Präsentationsschicht):
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            PlaybackManager.Instance.SongPositionChanged += new SongPositionChangedEventHandler(PlaybackManager_SongPositionChanged);
        }

        public delegate void SetSliderCallback(double percent);

        [...]

        void PlaybackManager_SongPositionChanged(object sender, SongPositionChangedEventArgs e)
        {
            SetSliderCallback callback = SetSlider;
            this.Dispatcher.Invoke(callback, new object[] { e.NewPosition});
        }



PlaybackManager-Klasse (Auszug) (Domänenschicht)
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
    public delegate void SongPositionChangedEventHandler(object sender, SongPositionChangedEventArgs e);

    public class PlaybackManager
    {
        public event SongPositionChangedEventHandler SongPositionChanged;

        protected virtual void OnSongPositionChanged(SongPositionChangedEventArgs e)
        {
            if (SongPositionChanged != null)
            {
                SongPositionChanged(this, e);
            }
        }

        [...]

        void SongTracker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = (BackgroundWorker)sender;
            ChannelAgent.ChannelObject o;

            while (!worker.CancellationPending)
            {
                try
                {
                    o = Channel.CurrentChannel;
                    double percent = o.Audio.CurrentPosition * 100 / o.Audio.Duration;
                    OnSongPositionChanged(new SongPositionChangedEventArgs(percent));
                }
                catch (NullReferenceException)
                {
                    break;
                }
                Thread.Sleep(500);
            }
        }
    }


Das Pattern MVVM ist mir sehr neu. So wie ich das verstanden habe, würdest du empfehlen WPF MIT MVVM zu benutzen? Ich werde mich darüber mal informieren.
Ich habe deshalb WPF gewählt, um erst einmal etwas von Windows.Forms loszukommen :)

Danke und lg,
Manuel