摆脱奇怪动画错误的一种方法是让Flyout控件的动画先运行,然后在动画完成后显示ListView。
为此,您需要订阅Flyout 控件中的以下事件。此外,您还需要为 ListView 命名并将其 Opacity 设置为 0 以开始。
<Flyout Opened="Flyout_Opened" Closed="Flyout_Closed">
<ListView x:Name="MyListView" Opacity="0" ItemsSource="{Binding Source={StaticResource ItemsViewSource}}" Margin="20 0">
然后在后面的代码中,您会在短暂延迟后显示ListView。我为ListView 创建了一个小Opacity 动画,只是为了让整个过渡运行更顺畅。每次Flyout 关闭时,我们都会将ListView 重置为不可见。
private async void Flyout_Opened(object sender, object e)
{
// a short delay to allow the Flyout in animation to take place
await Task.Delay(400);
// animate in the ListView
var animation = new DoubleAnimation
{
Duration = TimeSpan.FromMilliseconds(200),
To = 1
};
Storyboard.SetTarget(animation, this.MyListView);
Storyboard.SetTargetProperty(animation, "Opacity");
var storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
private void Flyout_Closed(object sender, object e)
{
this.MyListView.Opacity = 0;
}
但是,在提供了可能的解决方案后,我认为使用Flyout 控件来更改视觉样式并不是正确的方法。
Flyout 控件不是为处理大量数据而设计的。它不支持虚拟化(我认为)。例如,如果您将项目数从 30 增加到 300,则在您点击按钮后将需要相当多的时间来加载。
更新(包括工作示例)
我在想也许我可以创建一个控件来处理所有这些,因为最终您确实希望能够检索您在列表中单击的项目并关闭弹出窗口。
不幸的是ListPickerFlyout 被密封,所以我选择创建一个继承自Flyout 的控件。
这很简单。基本上,该控件公开了ItemsSource、SelectedItem 等属性。它还订阅了ListView 的ItemClick 事件,因此每当单击某个项目时,它都会关闭Flyout 并填充SelectedItem。
public class ListViewFlyout : Flyout
{
private ListView _listView;
public object ItemsSource
{
get { return (object)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(object), typeof(ListViewFlyout), new PropertyMetadata(null));
public DataTemplate HeaderTemplate
{
get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
set { SetValue(HeaderTemplateProperty, value); }
}
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(ListViewFlyout), new PropertyMetadata(null));
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(ListViewFlyout), new PropertyMetadata(null));
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(ListViewFlyout), new PropertyMetadata(null));
public ListViewFlyout()
{
// initialization
this.Placement = FlyoutPlacementMode.Full;
_listView = new ListView
{
Opacity = 0,
IsItemClickEnabled = true
};
this.Opened += ListViewFlyout_Opened;
this.Closed += ListViewFlyout_Closed;
}
private async void ListViewFlyout_Opened(object sender, object e)
{
await Task.Delay(400);
if (!_listView.Items.Any())
{
// assign the listView as the Content of this 'custom control'
_listView.ItemsSource = this.ItemsSource;
_listView.ItemTemplate = this.ItemTemplate;
_listView.GroupStyle.Add(new GroupStyle { HeaderTemplate = this.HeaderTemplate });
this.Content = _listView;
// whenever an item is clicked, we close the Layout and assign the SelectedItem
_listView.ItemClick += ListView_ItemClick;
}
// animate in the list
var animation = new DoubleAnimation
{
Duration = TimeSpan.FromMilliseconds(200),
To = 1
};
Storyboard.SetTarget(animation, _listView);
Storyboard.SetTargetProperty(animation, "Opacity");
var storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
private void ListViewFlyout_Closed(object sender, object e)
{
_listView.Opacity = 0;
}
private async void ListView_ItemClick(object sender, ItemClickEventArgs e)
{
this.SelectedItem = e.ClickedItem;
this.Hide();
// to be removed
await Task.Delay(1000);
var dialog = new MessageDialog(e.ClickedItem.ToString() + " was clicked 1 sec ago!");
await dialog.ShowAsync();
}
}
xaml 就这么简单。
<AppBarButton Icon="Caption">
<AppBarButton.Flyout>
<local:ListViewFlyout ItemsSource="{Binding Source={StaticResource ItemsViewSource}}" ItemTemplate="{StaticResource ListViewItemTemplate}" HeaderTemplate="{StaticResource GroupHeaderTemplate}" FlyoutPresenterStyle="{StaticResource FlyoutPresenterStyle}" />
</AppBarButton.Flyout>
</AppBarButton>
注意FlyoutPresenterStyle 样式我也为弹出窗口创建了Title。
我还包含了一个功能齐全的示例here。