Цитата(Rohoss @ 3.3.2011, 04:24 ) | | не должно иметь никакого кода, имеющего какого либо отношения к логике приложения |
К логике приложения да, не должно, а к логику привязки взаимодействия с моделью представления или логику самого представления внутри себя - пожалуйста.
Цитата(Rohoss @ 3.3.2011, 04:24 ) | | с использованием мессаджеров, так как о данных объектах я ничего не знаю |
Это не стандартные классы и поведение. В составе наших проектов мы используем самописный мессенджер. Он довольно тривиален и суть его такова, что любой объект в домене приложения может зарегистрироваться для получения сообщений определенного типа. Далее, любой объект может также отправлять сообщение какого-то типа и все зарегистрировавшиеся получатели его получают. Привести код этого класса я не могу, так как права на исходники принадлежат компании в которой я работаю, но я поискал щас в инете и нашел похожую реализацию http://www.galasoft.ch/mvvm/getstarted/. Правда как я понял, та реализация куда более тривиальна, чем наша, но подойдет для простых задач. Через мессенджер можно сделать так, чтобы view регистрировалась на получение сообщений своего типа. При получении сообщений, она выполняет соответствующие действия. Так как мессенджер является синглтон-объектом, то он доступен из любого места приложения и любая модель представления (не зависимо от того для чего она создана) в таком варианте может отправлять сообщения на воспроизведение звука или видео. Я приведу код мессенджера описывающий только идею без детальной реализации. Не берите за основу сигнатуры его методов, так как на самом деле нужно о многом позаботиться прежде, чем запоминать обработчик сообщения.
| Код | public class SimplestExampleMessenger { static SimplestExampleMessenger _instance = null; public static SimplestExampleMessenger Instance { get { return _instance ?? (_instance = new SimplestExampleMessenger()); } }
public void Register<TMsgType>(Action<TMsgType> handler) { // запоминаем где-нибудь кто и какой метод // хочет получать сообщения типа TMsgType } public void Send<TMsgType>(TMsgType message) { // у всех кто зарегился получение сообщения типа TMsgType // вызываем запомненный метод и передаем message в качестве параметра } }
|
А вот примерная идея реализации на основе мессенджера: 1) Классы сообщений проигрывателя
| Код | public abstract class MediaPlayerMessage { public abstract string Action { get; } public bool Handled { get; set; } public int Key { get; set; } } public class PlayMediaMessage : MediaPlayerMessage { public PlayMediaMessage(Stream source) { this.Source = source; } public Stream Source { get; private set; } public override string Action { get { return "play"; } } } public class StopMediaMessage : MediaPlayerMessage { public StopMediaMessage(int key) { this.Key = key; } public override string Action { get { return "stop"; } } }
|
2) Класс проигрывателя. Я сделал его пустым, так как ориентировался только на звук, который не имеет отображения. Нет никаких проблем сделать его таким, каким вы себе его представляете.
| Код | <UserControl x:Class="SilverlightApplication2.MediaPlayer" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Visibility="Collapsed"> </UserControl>
|
| Код | using System; using System.Collections.Generic; using System.Windows.Controls;
namespace SilverlightApplication2 { public partial class MediaPlayer : UserControl { int lastKeyID = 0; Dictionary<int, MediaElement> currentMediaList = null;
public MediaPlayer() { InitializeComponent(); currentMediaList = new Dictionary<int, MediaElement>(); SimplestExampleMessenger.Instance.Register<MediaPlayerMessage>(HandleMessage); }
public void HandleMessage(MediaPlayerMessage message) { if (message is PlayMediaMessage) { MediaElement media = new MediaElement(); message.Key = ++lastKeyID; currentMediaList.Add(message.Key, media); media.SetSource(((PlayMediaMessage)message).Source); media.MediaEnded += (s, e) => HandleMessage(new StopMediaMessage(message.Key)); media.Play(); message.Handled = true; } else if (message is StopMediaMessage) { MediaElement media = null; if (currentMediaList.TryGetValue(message.Key, out media)) { media.Stop(); currentMediaList.Remove(message.Key); } message.Handled = true; } } } }
|
Теперь, если у вас в любом месте UI где-то расположен MediaPlayer (его не видно и он не будет мешать), то вы можете проигрывать сколько угодно мелодий одновременно.
| Код | // воспроизвести MediaPlayerMessage message = new PlayMediaMessage(new MemoryStream(Resource1.Amanda)); SimplestExampleMessenger.Instance.Send(message); // message.Key теперь будет содержать идентификатор вашей мелодии mediaKey = message.Key;
.....................
// остановить SimplestExampleMessenger.Instance.Send(new StopMediaMessage(mediaKey));
|
Как видите, тут все очень просто. В этом примере даже близко нет ни упоминания ни использования MVVM. Всю задачу абстракции решает тут мессенджер. Код который отправляет сообщения, ничего не знает о проигрывателе. Проигрыватель вообще может не существовать и вызывающий код будет продолжать работать (просто беззвучно). А если отправляющей стороне необходимо знать проигрывается звук или нет, то я пердусмотрел в примере сообщения свойство Handled. MediaPlayer выставляет его в true, если она отработала сообщение. Также, вы можете в любой момент добавить новые поддерживаемые сообщения или заменить их обработчик например на DirectX. Абстрагировать через мессенджер можно даже несколько viewmodel между собой. В общем, думаю эта идея тут достаточно развернута, а мне пора идти гулять со своими детишками  |