Skip to content

Commit

Permalink
TabView fix for Issues #2455 & #2457
Browse files Browse the repository at this point in the history
  • Loading branch information
RBrid committed Jun 9, 2020
1 parent 28c4201 commit eb79688
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 2 deletions.
10 changes: 9 additions & 1 deletion dev/Generated/TabView.properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ void TabViewProperties::EnsureProperties()
winrt::name_of<winrt::TabView>(),
false /* isAttached */,
ValueHelper<winrt::IInspectable>::BoxedDefaultValue(),
nullptr);
winrt::PropertyChangedCallback(&OnTabItemsSourcePropertyChanged));
}
if (!s_TabItemTemplateProperty)
{
Expand Down Expand Up @@ -294,6 +294,14 @@ void TabViewProperties::OnSelectedItemPropertyChanged(
winrt::get_self<TabView>(owner)->OnSelectedItemPropertyChanged(args);
}

void TabViewProperties::OnTabItemsSourcePropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args)
{
auto owner = sender.as<winrt::TabView>();
winrt::get_self<TabView>(owner)->OnTabItemsSourcePropertyChanged(args);
}

void TabViewProperties::OnTabWidthModePropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args)
Expand Down
4 changes: 4 additions & 0 deletions dev/Generated/TabView.properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ class TabViewProperties
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);

static void OnTabItemsSourcePropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);

static void OnTabWidthModePropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);
Expand Down
106 changes: 106 additions & 0 deletions dev/TabView/TabView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,37 @@ TabView::TabView()

void TabView::OnApplyTemplate()
{
m_listViewLoadedRevoker.revoke();
m_listViewSelectionChangedRevoker.revoke();
m_listViewDragItemsStartingRevoker.revoke();
m_listViewDragItemsCompletedRevoker.revoke();
m_listViewDragOverRevoker.revoke();
m_listViewDropRevoker.revoke();
m_listViewGettingFocusRevoker.revoke();
m_listViewCanReorderItemsPropertyChangedRevoker.revoke();
m_listViewAllowDropPropertyChangedRevoker.revoke();
m_addButtonClickRevoker.revoke();
m_itemsPresenterSizeChangedRevoker.revoke();
m_scrollViewerLoadedRevoker.revoke();
m_scrollViewerViewChangedRevoker.revoke();
m_scrollDecreaseClickRevoker.revoke();
m_scrollIncreaseClickRevoker.revoke();

m_tabContentPresenter.set(nullptr);
m_rightContentPresenter.set(nullptr);
m_leftContentColumn.set(nullptr);
m_tabColumn.set(nullptr);
m_addButtonColumn.set(nullptr);
m_rightContentColumn.set(nullptr);
m_tabContainerGrid.set(nullptr);
m_shadowReceiver.set(nullptr);
m_listView.set(nullptr);
m_addButton.set(nullptr);
m_itemsPresenter.set(nullptr);
m_scrollViewer.set(nullptr);
m_scrollDecreaseButton.set(nullptr);
m_scrollIncreaseButton.set(nullptr);

winrt::IControlProtected controlProtected{ *this };

m_tabContentPresenter.set(GetTemplateChildT<winrt::ContentPresenter>(L"TabContentPresenter", controlProtected));
Expand Down Expand Up @@ -97,6 +128,9 @@ void TabView::OnApplyTemplate()
m_listViewDropRevoker = listView.Drop(winrt::auto_revoke, { this, &TabView::OnListViewDrop });

m_listViewGettingFocusRevoker = listView.GettingFocus(winrt::auto_revoke, { this, &TabView::OnListViewGettingFocus });

m_listViewCanReorderItemsPropertyChangedRevoker = RegisterPropertyChanged(listView, winrt::ListViewBase::CanReorderItemsProperty(), { this, &TabView::OnListViewDraggingPropertyChanged });
m_listViewAllowDropPropertyChangedRevoker = RegisterPropertyChanged(listView, winrt::UIElement::AllowDropProperty(), { this, &TabView::OnListViewDraggingPropertyChanged });
}
return listView;
}());
Expand Down Expand Up @@ -141,6 +175,13 @@ void TabView::OnApplyTemplate()
shadowCaster.Shadow(shadow);
}
}

UpdateListViewItemContainerTransitions();
}

void TabView::OnListViewDraggingPropertyChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args)
{
UpdateListViewItemContainerTransitions();
}

void TabView::OnListViewGettingFocus(const winrt::IInspectable& sender, const winrt::GettingFocusEventArgs& args)
Expand Down Expand Up @@ -211,6 +252,71 @@ void TabView::OnSelectedItemPropertyChanged(const winrt::DependencyPropertyChang
UpdateSelectedItem();
}

void TabView::OnTabItemsSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs&)
{
UpdateListViewItemContainerTransitions();
}

void TabView::UpdateListViewItemContainerTransitions()
{
if (TabItemsSource())
{
if (auto listView = m_listView.get())
{
if (listView.CanReorderItems() && listView.AllowDrop())
{
// Remove all the AddDeleteThemeTransition/ContentThemeTransition instances in the inner ListView's ItemContainerTransitions
// collection to avoid attempting to reparent a tab's content while it is still parented during a tab reordering user gesture.
// This is only required when:
// - the TabViewItem' contents are databound to UIElements (this condition is not being checked below though).
// - System animations turned on (this condition is not being checked below though to maximize behavior consistency).
// - TabViewItem reordering is turned on.
// With all those conditions met, the databound UIElements are still parented to the old item container as the tab is being dropped in
// its new location. Without animations, the old item container is already put into the recycling pool and picked as the new container.
// Its ContentControl.Content is kept unchanged and no reparenting is attempted.
// Because the default ItemContainerTransitions collection is defined in the TabViewListView style, all ListView instances share the same
// collection by default. Thus to avoid one TabView affecting all other ones, a new ItemContainerTransitions collection is created
// when the original one contains an AddDeleteThemeTransition or ContentThemeTransition instance.
bool transitionCollectionHasAddDeleteOrContentThemeTransition = [listView]()
{
if (auto itemContainerTransitions = listView.ItemContainerTransitions())
{
for (auto&& transition : itemContainerTransitions)
{
if (transition &&
(transition.try_as<winrt::AddDeleteThemeTransition>() || transition.try_as<winrt::ContentThemeTransition>()))
{
return true;
}
}
}
return false;
}();

if (transitionCollectionHasAddDeleteOrContentThemeTransition)
{
auto const newItemContainerTransitions = winrt::TransitionCollection();
auto const oldItemContainerTransitions = listView.ItemContainerTransitions();

for (auto&& transition : oldItemContainerTransitions)
{
if (transition)
{
if (transition.try_as<winrt::AddDeleteThemeTransition>() || transition.try_as<winrt::ContentThemeTransition>())
{
continue;
}
newItemContainerTransitions.Append(transition);
}
}

listView.ItemContainerTransitions(newItemContainerTransitions);
}
}
}
}
}

void TabView::OnTabWidthModePropertyChanged(const winrt::DependencyPropertyChangedEventArgs&)
{
UpdateTabWidths();
Expand Down
6 changes: 6 additions & 0 deletions dev/TabView/TabView.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class TabView :

// Internal
void OnCloseButtonOverlayModePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnTabItemsSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnTabWidthModePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnSelectedIndexPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnSelectedItemPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
Expand Down Expand Up @@ -147,7 +148,9 @@ class TabView :
void UpdateTabWidths();

void UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
void UpdateListViewItemContainerTransitions();

void OnListViewDraggingPropertyChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args);
void OnListViewGettingFocus(const winrt::IInspectable& sender, const winrt::GettingFocusEventArgs& args);

int GetItemCount();
Expand Down Expand Up @@ -175,6 +178,9 @@ class TabView :
winrt::Selector::SelectionChanged_revoker m_listViewSelectionChangedRevoker{};
winrt::UIElement::GettingFocus_revoker m_listViewGettingFocusRevoker{};

PropertyChanged_revoker m_listViewCanReorderItemsPropertyChangedRevoker{};
PropertyChanged_revoker m_listViewAllowDropPropertyChangedRevoker{};

winrt::ListView::DragItemsStarting_revoker m_listViewDragItemsStartingRevoker{};
winrt::ListView::DragItemsCompleted_revoker m_listViewDragItemsCompletedRevoker{};
winrt::UIElement::DragOver_revoker m_listViewDragOverRevoker{};
Expand Down
1 change: 1 addition & 0 deletions dev/TabView/TabView.idl
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ unsealed runtimeclass TabView : Windows.UI.Xaml.Controls.Control
event Windows.Foundation.TypedEventHandler<TabView, Windows.Foundation.Collections.IVectorChangedEventArgs> TabItemsChanged;

// From ListView
[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)]
Object TabItemsSource;
Windows.Foundation.Collections.IVector<Object> TabItems{ get; };

Expand Down
3 changes: 2 additions & 1 deletion dev/TabView/TestUI/TabViewPage.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. See LICENSE in the project root for license information. -->
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. See LICENSE in the project root for license information. -->
<local:TestPage
x:Class="MUXControlsTestApp.TabViewPage"
x:Name="TabViewTestPage"
Expand Down Expand Up @@ -154,6 +154,7 @@
<StackPanel x:Name="FirstTabContent" AutomationProperties.Name="FirstTabContent">
<Button x:Name="FirstTabButton" AutomationProperties.Name="FirstTabButton" Margin="8" FontSize="20">Home Button</Button>
<Button x:Name="TabViewSizingPageButton" AutomationProperties.Name="TabViewSizingPageButton" Margin="8" Click="TabViewSizingPageButton_Click" FontSize="20">TabView Sizing Page</Button>
<Button x:Name="TabViewTabItemsSourcePageButton" AutomationProperties.Name="TabViewTabItemsSourcePageButton" Margin="8" Click="TabViewTabItemsSourcePageButton_Click" FontSize="20">TabView TabItemsSource Page</Button>
</StackPanel>
</controls:TabViewItem>

Expand Down
5 changes: 5 additions & 0 deletions dev/TabView/TestUI/TabViewPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,11 @@ private void TabViewSizingPageButton_Click(object sender, RoutedEventArgs e)
this.Frame.Navigate(typeof(TabViewSizingPage));
}

private void TabViewTabItemsSourcePageButton_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(TabViewTabItemsSourcePage));
}

private void ShortLongTextButton_Click(object sender, RoutedEventArgs e)
{
FirstTab.Header = "s";
Expand Down
39 changes: 39 additions & 0 deletions dev/TabView/TestUI/TabViewTabItemsSourcePage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<Page
x:Class="MUXControlsTestApp.TabViewTabItemsSourcePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MUXControlsTestApp"
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<controls:TabView x:Name="TabViewItemsSourceSample"
Margin="5"
SelectedIndex="0"
MinHeight="200"
TabItemsSource="{x:Bind myDatas, Mode=OneWay}"
AddTabButtonClick="TabViewItemsSourceSample_AddTabButtonClick"
TabCloseRequested="TabViewItemsSourceSample_TabCloseRequested">
<controls:TabView.TabItemTemplate>
<DataTemplate x:DataType="local:MyData">
<controls:TabViewItem
Header="{x:Bind DataHeader}"
IconSource="{x:Bind DataIconSource}"
Content="{x:Bind DataContent}"/>
</DataTemplate>
</controls:TabView.TabItemTemplate>
</controls:TabView>
<StackPanel Margin="5" Grid.Row="1">
<CheckBox x:Name="chkCanDragItems" Content="ListView.CanDragItems?" IsChecked="False" Checked="ChkCanDragItems_Checked" Unchecked="ChkCanDragItems_Unchecked"/>
<CheckBox x:Name="chkCanReorderItems" Content="ListView.CanReorderItems?" IsChecked="True" Checked="ChkCanReorderItems_Checked" Unchecked="ChkCanReorderItems_Unchecked"/>
<CheckBox x:Name="chkCanDrag" Content="ListView.CanDrag?" IsChecked="False" Checked="ChkCanDrag_Checked" Unchecked="ChkCanDrag_Unchecked"/>
<CheckBox x:Name="chkAllowDrop" Content="ListView.AllowDrop?" IsChecked="True" Checked="ChkAllowDrop_Checked" Unchecked="ChkAllowDrop_Unchecked"/>
</StackPanel>
</Grid>
</Page>
Loading

0 comments on commit eb79688

Please sign in to comment.