2011-07-14 76 views
0

什麼是正確的方式讓我的視圖模型觸發自定義查找控件拋出一個實質上表示查找視圖模型的模態對話框?自定義查找控件的數據上下文是父記錄視圖模型的上下文。查找控件還有另一個DependencyProperty,它綁定到父記錄視圖模型上的lookupviewmodel屬性,並表示子查找視圖模型。獲取查找視圖模型來觸發模態對話框

方法1)我當前在lookupviewmodel上使用自定義控件知道要偵聽的事件。

方法2)我試圖在查找控件的文本行爲綁定的lookupviewmodel屬性的setter中拋出一個驗證異常。然後我在自定義查找控件中掛接了ErrorEvent。但是,在這種情況下,如果用戶在對話框中「修正」了對話框中的值,那麼原始值就會出現。更糟糕的是,即使在我調用Validation.ClearInvalid之後,另一個ErrorEvent仍會觸發,以某種方式將錯誤添加回來。所以一切都在這裏工作,因爲所有的視圖模型都有正確的數據,就好像文本框忽略了在ErrorEvent中綁定的文本屬性在基礎數據源上發生了變化。所以看起來我不能在錯誤處理過程中糾正錯誤?

方法2中的另一個子問題是Validation.ClearInvalid不會刪除紅色錯誤邊框。我也必須手動清除ErrorTemplate。是對的嗎?

我想找到一種方法來使用控件中的自然錯誤處理,讓它拋出模態對話框。

回答

1

這不是你使用的事件。存在的事件有助於解耦:提升事件的對象不應該知道或關心正在聆聽的對象在做什麼。你期望一個事件能夠從屬性的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框架,你會發現它們中的很多都實現了這種或那種對話服務。

+0

我讀過關於DialogService甚至Mediator。我想我只是被撕裂,特別是在這個話題上有多少爭論。誰應該負責拋出GUI元素,視圖或視圖模型?如果我使用DialogService,那麼無論使用什麼或在哪裏或使用什麼控件,屬性設置器都會失敗,它會拋出一個對話框。如果設計者沒有實現對話會怎麼樣?我試圖想出一種方法,讓觀看模型不以任何方式關心GUI元素的形狀或形式。他們驗證,並且它失敗了,該觀點決定是否要採取行動。 – happyfirst

+0

我可能最終需要其他類型的對話框的DialogService,但我不想放棄驗證查找對話框。我現在所做的是我的LookupViewModel有一個bool ShowModalDialog propery,通過INotifyProperyChanged監視自定義查找控件。如果驗證失敗,查找視圖模型將其設置爲true,並顯示模式,用戶可以選擇新值或取消。對話結果將它返回給將ShowModalDialog設置爲true的屬性設置器,並且它的結果不是真,它會引發驗證異常。 – happyfirst

+0

視圖模型請求對話框並處理響應。 WPF對話服務本質上是視圖的一部分。關注點分開:視圖模型不知道對話是如何實現的,它只知道它需要用戶的響應並獲得它。 –

0

您可以使用像MVVMLight或Prism這樣的框架,它允許您以完全分離的方式在不同實體之間傳遞有效載荷。與Prism相比,MVVMLight非常輕巧。它有一個Messanger的概念,作爲一個系統範圍的事件公共汽車。同樣你在Prism中有EventAggregator。