在CM源的ShowDialog()
實現:
public virtual void ShowDialog(object rootModel, object context = null, IDictionary<string, object> settings = null)
{
var view = EnsureWindow(rootModel, ViewLocator.LocateForModel(rootModel, null, context));
ViewModelBinder.Bind(rootModel, view, context);
var haveDisplayName = rootModel as IHaveDisplayName;
if(haveDisplayName != null && !ConventionManager.HasBinding(view, ChildWindow.TitleProperty)) {
var binding = new Binding("DisplayName") { Mode = BindingMode.TwoWay };
view.SetBinding(ChildWindow.TitleProperty, binding);
}
ApplySettings(view, settings);
new WindowConductor(rootModel, view);
view.Show();
}
完整的源代碼在這裏:
http://caliburnmicro.codeplex.com/SourceControl/changeset/view/ae25b519bf1e46a506c85395f04aaffb654c0a08#src/Caliburn.Micro.Silverlight/WindowManager.cs
它看起來並不像有一個與默認實現做到這一點的好辦法。你或許應該實現自己的WindowManager
,並繼承原執行
在上面的代碼文件的WindowConductor
負責窗口的生命週期,因此和額外的接口,你的虛擬機可以實現將工作做好:
public interface ICancelActivate
{
public bool ActivationCancelled { get };
}
然後,只需改變你的MyWindowConductor
實施類似:
public MyWindowConductor(object model, ChildWindow view)
{
// Added this field so the window manager can query the state of activation (or use a prop if you like)
public bool ActivationCancelled;
this.model = model;
this.view = view;
var activatable = model as IActivate;
if (activatable != null)
{
activatable.Activate();
}
// Added code here, check to see if the activation was cancelled:
var cancelActivate = model as ICancelActivate;
if(cancelActivate != null)
{
ActivationCancelled = cancelActivate.ActivationCancelled;
if(ActivationCancelled) return; // Don't bother handling the rest of activation logic if cancelled
}
var deactivatable = model as IDeactivate;
if (deactivatable != null) {
view.Closed += Closed;
deactivatable.Deactivated += Deactivated;
}
var guard = model as IGuardClose;
if (guard != null) {
view.Closing += Closing;
}
}
然後停止展示的觀點:
// This is in 'ShowDialog' - you can override the default impl. as the method is marked virtual
ApplySettings(view, settings);
// Get a ref to the conductor so you can check if activation was cancelled
var conductor = new MyWindowConductor(rootModel, view);
// Check and don't show if we don't need to
if(!conductor.ActivationCancelled)
view.Show();
顯然我剛拋出這個在一起,因此它可能不是最好的辦法,而且我在這個地方留下你的應用程序的
你的虛擬機只是實現這個狀態仔細看:
public class StationOpenViewModel : Screen, ICancelActivation {
private bool _activationCancelled;
public bool ActivationCancelled { get { return _activationCancelled; } }
...
protected override void OnActivate() {
try {
using (StationRepository stationRepository = new StationRepository()) {
//code to get Station Data
}
catch (Exception ex) {
_activationCancelled = true;
}
...
}
...當然可能會有更好的辦法讓你檢查,如果你需要首先打開一個虛擬機 - 我不知道他們會是什麼,但仍,值得我們思考的
編輯:
我之所以不在WindowManager
中這麼做...
new WindowConductor(rootModel, view);
var cancel = rootModel as ICancelActivation;
if(cancel == null || !cancel.ActivationCancelled) // fixed the bug here!
view.Show();
是雙重的 - 1:你還在讓WindowConductor
添加停用和GuardClose掛鉤,即使他們不應該被使用,這可能導致一些不良的行爲(不知道基準保持或者 - 可能確定與此一次,因爲沒有任何持有裁判指揮/虛擬機)
2:它似乎像WindowConductor激活虛擬機應負責處理取消激活 - 確定這意味着WindowManager
需要知道是否以顯示虛擬機或不虛擬,但它似乎更適合我自己
編輯2:
一個想法可能是移動view.Show()到導體 - 這樣你可以取消激活而無需暴露細節的經理。兩者都相互依賴,所以它對我來說都是一樣的
看起來很合理,因爲我有很多Windows需要處理。在你的答案中實現你提供的WindowManager和Conductor似乎是很好的。但我仍然有疑問。爲什麼我們需要在這裏帶上導體?我的意思是爲什麼MyWindowManager不能直接從rootModel查詢ICancelActivate,並且自己取消創建對話框。我的意思是爲什麼我們需要通過售票員? – Jatin 2013-04-22 11:21:00
我這樣做的原因是,指揮有管理窗口生命週期(佈線事件等)的工作,所以你將VM的激活傳遞給另一個組件。虛擬機進入這個黑匣子,你無法控制是否實際添加了deactivate和guardclose鉤子(儘管它永遠不會顯示)。它可能會在您的代碼中引入一個不明確的錯誤 - (不知道是什麼,但最好是安全的!) – Charleh 2013-04-22 11:27:23
我想另一種方法是將view.Show()放入指示器,可能會稍微整理一下實現...它似乎是指揮應該負責顯示窗口 - 這是一個混合..經理是嚴重依賴於指揮 – Charleh 2013-04-22 11:39:06