這不是你使用的事件。存在的事件有助於解耦:提升事件的對象不應該知道或關心正在聆聽的對象在做什麼。你期望一個事件能夠從屬性的setter中改變一個屬性的值 - 或者更糟的是,你的事件處理器正在調用那個正在處理它的事件的屬性setter,這意味着你必須做一些事情相當hackish以避免堆棧溢出。
您的描述不是很清楚(您正在描述您遇到的問題以及您在同一時間嘗試的非工作解決方案,這很令人困惑),但是這聽起來像是你的「再試圖做的是更多的東西一樣:
if (IsValid(value))
{
_Property = value;
}
else
{
_Property = GetValueFromDialog();
}
的問題是,你不希望有代碼拋出了一個對話框,您的視圖模型,因爲它創建無法測試一個視圖模型在你的WPF應用程序之外。
在這種情況下的答案是使用依賴注入。創建一個名爲IDialogService
接口:
interface IDialogService
{
object GetValueFromDialog();
}
現在這個屬性添加到您的視圖模型:
public IDialogService DialogService { get; set; }
上面的代碼變成:
if (IsValid(value))
{
_Property = value;
}
else
{
_Property = DialogService.GetValueFromDialog();
}
在您的WPF應用創建一個對話框服務實際拋出對話框並獲得結果的應用程序。當您在應用程序實例化視圖模型,這樣做:
MyViewModel vm = new MyViewModel { DialogService = new WpfDialogService(); }
因此,在應用程序中,屬性setter會提出了對話框,你希望它得到的結果完全吻合。
對於你的單元測試,創建一個模擬對話,看起來像這樣:
public class MockDialogService : IDialogService
{
private object Result;
public MockDialogService(object result)
{
Result = result;
}
public object GetValueFromDialog() { return Result; }
}
然後,您可以寫這樣一個測試:
MyViewModel vm = new MyViewModel { DialogService = MockDialogService(ExpectedResult) };
vm.Property = InvalidValue;
Assert.AreEqual(ExpectedResult, vm.Property);
以上是一個解決方案確實更草圖而不是解決方案 - 取決於您的應用程序如何使用對話框,您可能需要比此處概述的更多功能。如果你看看MVVM框架,你會發現它們中的很多都實現了這種或那種對話服務。
我讀過關於DialogService甚至Mediator。我想我只是被撕裂,特別是在這個話題上有多少爭論。誰應該負責拋出GUI元素,視圖或視圖模型?如果我使用DialogService,那麼無論使用什麼或在哪裏或使用什麼控件,屬性設置器都會失敗,它會拋出一個對話框。如果設計者沒有實現對話會怎麼樣?我試圖想出一種方法,讓觀看模型不以任何方式關心GUI元素的形狀或形式。他們驗證,並且它失敗了,該觀點決定是否要採取行動。 – happyfirst
我可能最終需要其他類型的對話框的DialogService,但我不想放棄驗證查找對話框。我現在所做的是我的LookupViewModel有一個bool ShowModalDialog propery,通過INotifyProperyChanged監視自定義查找控件。如果驗證失敗,查找視圖模型將其設置爲true,並顯示模式,用戶可以選擇新值或取消。對話結果將它返回給將ShowModalDialog設置爲true的屬性設置器,並且它的結果不是真,它會引發驗證異常。 – happyfirst
視圖模型請求對話框並處理響應。 WPF對話服務本質上是視圖的一部分。關注點分開:視圖模型不知道對話是如何實現的,它只知道它需要用戶的響應並獲得它。 –