Coproject – demo RIA aplikace krok za krokem, díl 14
V minulém díle jsme si vytvořili LazyScreen, který slouží k načítání view modelu až ve chvíli, kdy ho chce uživatel opravdu zobrazit. Dnes bych chtěl tuto funkcionalitu dotáhnout do konce a vytvořit Conductor, který bude podporovat toto zpožděné načítání view modelů a bude je také správně zavírat.
LazyConductor
Ve složce Framework vytvořte soubor LazyConductorWithCollectionOneActive.cs a vložte do něj tento kód:
public partial class LazyConductor
{
public partial class Collection
{
public class OneActive : Conductor>.Collection.OneActive
{
}
}
}
Když budu dále zmiňovat LazyConductor, budu tím myslet třídu OneActive.
Hlavní rozdíl mezi Conductorem a LazyConductorem je v tom, jakým způsobem zavírají vnořené view modely. Původní Conductor view model jednoduše odstraní ze své kolekce Items. Tím by však došlo k tomu, že view model zmizí z našeho menu. LazyConductor by místo toho měl tedy pouze zavolat funkci Reset() na vnořeném prvku (bude to LazyScreen) a případně přepnout na jiný již otevřený view model. Budeme tedy muset přepsat funkce pro zavírání/deaktivaci vnořených view modelů.
Přidejte do LazyConductoru následující funkci:
public override void DeactivateItem(LazyScreen item, bool close)
{
if (item == null)
{
return;
}
if (close)
{
CloseStrategy.Execute(new[] { item }, (canClose, closable) =>
{
if (canClose)
{
CloseItemCore(item);
}
});
}
else
{
ScreenExtensions.TryDeactivate(item, false);
}
}
Když porovnáte tuto funkci s tou původní z Caliburn.Micro, zjistíte, že nedošlo k žádně změně. My totiž potřebujeme změnit hlavně funkci CloseItemCore, která je ale private, a tím pádem musíme přepsat i funkci, která ji volá. Naše nová CloseItemCore pak bude vypadat následovně:
private void CloseItemCore(LazyScreen item)
{
if (item.Equals(ActiveItem))
{
var next = DetermineNextItemToActivate(item);
ChangeActiveItem(next, true);
}
else
{
ScreenExtensions.TryDeactivate(item, true);
}
item.Reset();
}
Zde je důležitý poslední řádek – v původní funkci je “Items.Remove(item)”. Tím zajistíme, že vnořený view model nebude odstraněn z menu, ale dojde pouze k jeho zavření.
Aby šla solution opět zkompilovat, musíme přidat ještě tuto funkci:
protected LazyScreen DetermineNextItemToActivate(
LazyScreen currentItem)
{
var next = Items.FirstOrDefault(x => x != currentItem && x.IsScreenCreated);
return next;
}
Na závěr ještě upravíme některé pomocné funkce z původního Conductoru.
public override void CanClose(Action<bool> callback)
{
var openedItems = Items.Where(x => x.IsScreenCreated);
CloseStrategy.Execute(openedItems, (canClose, closable) =>
{
closable.Apply(CloseItemCore);
callback(canClose);
});
}
protected override LazyScreen EnsureItem(LazyScreen newItem)
{
var node = newItem as IChild;
if (node != null && node.Parent != this)
{
node.Parent = this;
}
return newItem;
}
Důležitý je hlavně první řádek v CanClose – chceme brát v úvahu pouze již otevřené view modely.
ShellViewModel
Teď už jen zbývá upravit ShellViewModel. Upravte jeho definici takto:
public class ShellViewModel : LazyConductor.Collection.OneActive, IShell
Aby bylo možné zavírat moduly kliknutím na zavírací tlačítko v ShellView, musíme přidat potřebné funkce do view modelu:
public bool CanCloseActiveItem
{
get
{
return ActiveItem != null;
}
}
public void CloseActiveItem()
{
DeactivateItem(ActiveItem, true);
}
Aby se správně aktualizovala hodnota CanCloseActiveItem, přidejte ještě toto do konstruktoru:
this.PropertyChanged += (s, e) =>
{
if (e.PropertyName == "ActiveItem")
{
NotifyOfPropertyChange(() => CanCloseActiveItem);
}
};
ShellView
Vlastní zavírací tlačítko do ShellView už přidáme snadno. Otevřete ShellView.xaml a nejprve přidejte tuto definici:
xmlns:local="clr-namespace:Coproject.Controls"
Tlačítko pak vložte na konec gridu LayoutRoot:
"CloseActiveItem" ImageName="Close" ToolTipService.ToolTip="Close current module"
Margin="20" HorizontalAlignment="Right" VerticalAlignment="Top" />
A to je vše! Když teď otevřete modul To Do, upravíte nějakou položku a před uložením se pokusíte view model zavřít, uvidíte dokonce hlášku o neuložených změnách: