Reputation: 2282
Here I have a functional CloseTabAction using Prism 6 Toolkit found below:
class CloseTabAction : TriggerAction<Button>
{
protected override void Invoke(object parameter)
{
var args = parameter as RoutedEventArgs;
if (args == null) return;
var tabItem = FindParent<TabItem>(args.OriginalSource as DependencyObject);
if (tabItem == null) return;
var tabControl = FindParent<TabControl>(tabItem);
if (tabControl == null) return;
var region = RegionManager.GetObservableRegion(tabControl).Value;
if (region == null) return;
if (region.Views.Contains(tabItem.Content))
{
region.Remove(tabItem.Content);
}
}
static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
while (true)
{
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null) return null;
var parent = parentObject as T;
if (parent != null) return parent;
child = parentObject;
}
}
}
My problem is I want to close the TabItem only if the user selects 'Yes' (Saves to database and closes) or 'No' (Does not save but closes the tab).
I've created a custom popup window to do this however I'm not sure how to wire it up to the CloseTabAction. How would it know if the conformation is true or false?
This is a rough idea:
if (region.Views.Contains(tabItem.Content) && Status)
{
region.Remove(tabItem.Content);
}
public bool Status { get; set; }
private void RaiseClosePopup()
{
ClosePopupRequest.Raise(new Confirmation{Title = "Confrim", Content = "Are you sure you want to close this view?"}, r => Status = r.Confirmed);
}
Upvotes: 1
Views: 215
Reputation: 2282
In the invoke method I added this block of code. It checks if it implements my custom 'IConfrimCloseRequest' Interface, then calls the 'ConfrimCloseRequest' Method based from that result close or cancel. If it doesn't implement the interface just close it anyway.
var context = new NavigationContext(region.NavigationService, null);
if (IfImplements<IConfirmCloseRequest>(tabItem.Content,
i => i.ConfirmCloseRequest(context, canClose =>
{
if (!canClose) return;
if (region.Views.Contains(tabItem.Content))
region.Remove(tabItem.Content);
}))) return;
if (region.Views.Contains(tabItem.Content))
region.Remove(tabItem.Content);
private static T Implementor<T>(object content) where T : class
{
T implementor = content as T;
if (implementor != null) return implementor;
var element = content as FrameworkElement;
if (element != null) implementor = element.DataContext as T;
return implementor;
}
private static bool IfImplements<T>(object content, Action<T> action) where T : class
{
T target = Implementor<T>(content);
if (target == null) return false;
action(target);
return true;
}
Here In my ViewModel I implement my custom Interface with the method 'ConfirmCloseRequest' which will be called when closing the tab.
public void ConfirmCloseRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
ClosePopupRequest.Raise(new Confirmation { Title = "Confrim", Content = "Are you sure you want to close this view?" }, r => { continuationCallback(r.Confirmed); });
}
Upvotes: 0
Reputation:
I see you watched my Pluralsight course on mastering the TabControl with Prism :)
Why don't you just show a dialog before you call "Remove". If the result of the dialog is valid, then continue to remove, if not then don't remove. Then you just need to decide how you will notify your ViewModel of the action. This can be done a number of ways; event aggregator, expose a property on your CloseTabAction trigger, expose a command on your trigger. You can decide how you want to do that.
EDIT: I actually though of a better way. Just use an interface off of your ViewModel that you check to see if you can close a TabItem. Maybe use the IConfirmNavigationRequest interface or create your own. Then check that before removing he region. That's even easier.
Upvotes: 1