我明白,ViewModel不應該有任何關於視圖的知識,但我怎麼能從ViewModel調用MediaElement.Play()方法,除了有一個引用視圖(或直接MediaElement)在ViewModel中?
其他(鏈接)的問題:如何管理視圖的ViewModel控件可見性而不違反MVVM模式?MVVM模式違規:MediaElement.Play()
回答
1)不要從視圖模型中調用Play()
。提高在視圖模型的事件,而不是(例如PlayRequested
),並聽取這一事件的看法:
視圖模型:
public event EventHandler PlayRequested;
...
if (this.PlayRequested != null)
{
this.PlayRequested(this, EventArgs.Empty);
}
觀點:
ViewModel vm = new ViewModel();
this.DataContext = vm;
vm.PlayRequested += (sender, e) =>
{
this.myMediaElement.Play();
};
2)您可以公開在視圖模型中使用公共布爾屬性,並將控件的Visibility
屬性綁定到此屬性。由於Visibility
是Visibility
類型,而不是bool
,因此您必須使用轉換器。
你可以找到這種轉換器的基本實現here。 這related question也可能會幫助你。
非常感謝!PS:無需轉換,如果我公開可見性屬性,而不是一個bool一個 – italianogrosso
更好地利用布爾與轉換器的 – Zabavsky
@italianogrosso不客氣。 :)但是你不應該暴露一個'Visibility'類型的屬性。這個枚舉位於'System.Windows'命名空間中,正如命名空間所說 - 它意味着它完全與應用程序的視圖方面相關。真的,即使它需要更多的代碼,最好公開一個與視圖無關的布爾值。 – ken2k
當應用程序中發生事件時,我使用媒體元素在UI中播放聲音。處理這個的視圖模型是使用Uri類型的Source屬性創建的(通知屬性已更改,但您已經知道需要通知UI)。
所有你需要做的,每當源的變化(這是由你),是設置源屬性設置爲null(這就是爲什麼來源屬性應該是開放的,而不是字符串的MediaElement自然會拋出異常,引發NotSupportedException我想想),然後將其設置爲任何你想要的URI。
也許,本技巧最重要的一點是,您必須將MediaElement的屬性LoadedBehaviour設置爲在視圖的XAML中播放。希望不需要任何代碼就可以達到目的。
這個技巧非常簡單,所以我不會發表一個完整的例子。視圖模型的播放功能應該是這樣的:
private void PlaySomething(string fileUri)
{
if (string.IsNullOrWhiteSpace(fileUri))
return;
// HACK for MediaElement: to force it to play a new source, set source to null then put the real source URI.
this.Source = null;
this.Source = new Uri(fileUri);
}
下面是關於它的來源屬性,沒有什麼特別的:
#region Source property
/// <summary>
/// Stores Source value.
/// </summary>
private Uri _Source = null;
/// <summary>
/// Gets or sets file URI to play.
/// </summary>
public Uri Source
{
get { return this._Source; }
private set
{
if (this._Source != value)
{
this._Source = value;
this.RaisePropertyChanged("Source");
}
}
}
#endregion Source property
至於知名度,這樣的東西,你可以使用轉換器(例如從bool到可見性,您可以在CodePlex上找到WPF,SL,WP7,8),並將控件的屬性與視圖模型的屬性(例如IsVisible)綁定。這樣,你可以控制部分視圖的方面。或者你可以在視圖模型上使用Visibility屬性類型System.Windows.Visibility(我在這裏沒有看到任何模式違規)。真的,這並不罕見。
祝你好運,
安德烈
附:我必須提到的是,.NET 4.5是我測試過的版本,但我認爲它也適用於其他版本。
對於所有的後來者,
有很多方法來達到同樣的效果,它真的取決於你想如何實現你的,只要你的代碼是不是難以維持,怎麼辦相信在某些情況下可以打破MVVM模式。
但說了這麼多,我也相信在模式中總有辦法做到這一點,以下是其中之一,以防萬一任何人想知道其他替代品是否可用。
的任務:
- 我們不希望有從視圖模型到任何UI元素,即中的MediaElement和視圖本身直接引用。
- 我們要使用命令在這裏做
解決方案的魔力:
總之,我們要介紹的視圖和視圖模型之間的界面,打破的關係是不,View將實現接口並負責直接控制MediaElement,同時讓ViewModel只與接口交流,如果需要的話可以與其他實現交換以用於測試目的,下面是長版本:
介紹叫IMediaService的界面如下:
public interface IMediaService { void Play(); void Pause(); void Stop(); void Rewind(); void FastForward(); }
在View落實IMediaService:
public partial class DemoView : UserControl, IMediaService { public DemoView() { InitializeComponent(); } void IMediaService.FastForward() { this.MediaPlayer.Position += TimeSpan.FromSeconds(10); } void IMediaService.Pause() { this.MediaPlayer.Pause(); } void IMediaService.Play() { this.MediaPlayer.Play(); } void IMediaService.Rewind() { this.MediaPlayer.Position -= TimeSpan.FromSeconds(10); } void IMediaService.Stop() { this.MediaPlayer.Stop(); } }
我們然後做幾件事情在DemoView。XAML:
- 給這個MediaElement的一個名稱,以便後面的代碼可以像上面訪問:
<MediaElement Source="{Binding CurrentMedia}" x:Name="MediaPlayer"/>
- 給視圖的名稱,所以我們可以把它作爲一個參數和
- 導入交互性名稱空間供以後使用(由於簡單原因,某些默認名稱空間被省略):
<UserControl x:Class="Test.DemoView" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ia="http://schemas.microsoft.com/expression/2010/interactivity" x:Name="MediaService">
- 聯播通過觸發Loaded事件通過命令
<ia:Interaction.Triggers> <ia:EventTrigger EventName="Loaded"> <ia:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=MediaService}"></ia:InvokeCommandAction> </ia:EventTrigger> </ia:Interaction.Triggers>
- 最後但並非通過視圖本身向視圖模型至少,我們需要通過命令okup媒體控件:
<Button Command="{Binding PlayCommand}" Content="Play"></Button> <Button Command="{Binding PauseCommand}" Content="Pause"></Button> <Button Command="{Binding StopCommand}" Content="Stop"></Button> <Button Command="{Binding RewindCommand}" Content="Rewind"></Button> <Button Command="{Binding FastForwardCommand}" Content="FastForward"></Button>
現在,我們可以在視圖模型捕獲一切(我在這裏使用棱鏡的DelegateCommand):
public class AboutUsViewModel : SkinTalkViewModelBase, IConfirmNavigationRequest { public IMediaService {get; private set;} private DelegateCommand<IMediaService> loadedCommand; public DelegateCommand<IMediaService> LoadedCommand { get { if (this.loadedCommand == null) { this.loadedCommand = new DelegateCommand<IMediaService>((mediaService) => { this.MediaService = mediaService; }); } return loadedCommand; } } private DelegateCommand playCommand; public DelegateCommand PlayCommand { get { if (this.playCommand == null) { this.playCommand = new DelegateCommand(() => { this.MediaService.Play(); }); } return playCommand; } } . . // other commands are not listed, but you get the idea . }
方注意:我使用Prism的自動佈線功能來連接View和ViewModel。所以在View的代碼隱藏文件中沒有DataContext賦值代碼,我更喜歡這樣保留,因此我選擇使用純粹的Commands來實現這個結果。
- 1. MVVM違規
- 2. RelayCommand是否違反MVVM模式?
- 3. CollectionViewSource違反MVVM
- 4. ASP.NET MVVM模式
- 5. MVVM模式javascript
- 6. AndroidBlockGuardPolicy.onReadFromDisk FileInputStream違規
- 7. Javascript JSLint:ADsafe違規
- 8. PMD - 違規:SuspiciousEqualsMethodName
- 9. H2 ADA違規
- 10. Cross.Thread違規
- 11. 關於ODR違規和模板變量
- 12. 使用React Bootstrap模式的未捕獲不變違規
- 13. 嚴格模式返回此沒有w/o違規
- 14. Eclipse:檢查式違規圖標裝飾
- 15. MVVM模式查詢
- 16. MVVM模式和startActivity
- 17. MVVM模式書籍?
- 18. 使用MVVM模式
- 19. 奇怪段違規
- 20. java.lang.SecurityException:密封違規:
- 21. DrRacket合同違規
- 22. Git,違規提交
- 23. C++訪問違規?
- 24. Java replaceAll()&split()違規
- 25. 隱私違規Checkmarx
- 26. 完整性違反違規:Magento
- 27. 爲什麼違反FK違規的SqlException不會顯示違規值?
- 28. 模式是MVVM中的反模式嗎?
- 29. MVVM模式的模板形式
- 30. 正在訪問總是違反MVVM模式的代碼中的ViewModel?
鏈接的問題是不存在的.. :( – rydev