Использование индикатора прогресса, который скрыт в элементе управления Panorama, приводит к тому, что элемент панорамы становится только первым
У меня действительно странная и раздражающая проблема с моим приложением WP8.
Он использует элемент управления Panorama для просмотра элементов, которые он загружает из сети. У него есть представление, которое отображается во время загрузки контента, но затем сворачивается после завершения загрузки контента.
Когда представление "загрузка" свернуто, я обнаружил, что элемент управления Panorama возвращается к первому элементу элемента управления независимо от того, какой элемент выбран.
У меня есть следующий очень простой тестовый код, который демонстрирует проблему.
XAML:
<phone:PhoneApplicationPage
x:Class="Wp8.GUI.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="clr-namespace:Wp8.Gui.Converters"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Grid.Resources>
<phone:Panorama ItemsSource="{Binding PanoramaItems}">
<phone:Panorama.HeaderTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Title}" />
</Grid>
</DataTemplate>
</phone:Panorama.HeaderTemplate>
<phone:Panorama.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel x:Name="Visible1" Visibility="{Binding ShowFirst, Converter={StaticResource BooleanToVisibilityConverter},ConverterParameter=True}" >
<ProgressBar IsIndeterminate="True" />
<TextBlock Text="ShowFirst" />
</StackPanel>
<StackPanel x:Name="Visible2" Visibility="{Binding ShowFirst, Converter={StaticResource BooleanToVisibilityConverter},ConverterParameter=False}" >
<TextBlock Text="Show Second" />
</StackPanel>
</Grid>
</DataTemplate>
</phone:Panorama.ItemTemplate>
</phone:Panorama>
</Grid>
</phone:PhoneApplicationPage>
ВМ и код позади:
namespace Wp8.GUI
{
public class PanItemVm : INotifyPropertyChanged
{
private readonly string _title;
private bool _showFirst = true;
public PanItemVm()
{
_title = "Control";
}
public PanItemVm(string title)
{
_title = title;
}
public string Title { get { return _title; } }
public bool ShowFirst
{
get { return _showFirst; }
set
{
_showFirst = value;
RaisePropertyChanged("ShowFirst");
}
}
private void RaisePropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class PanItemVm2 : PanItemVm
{
public PanItemVm2() : base ("Items")
{
Task.Run(() => Task.Delay(TimeSpan.FromSeconds(5)))
.ContinueWith(t => ShowFirst = false,
TaskScheduler.FromCurrentSynchronizationContext());
}
}
public class TestVm : INotifyPropertyChanged
{
public IEnumerable<PanItemVm> PanoramaItems
{
get {
return Enumerable.Range(0, 2)
.Select(i => i == 0 ?
new PanItemVm() : new PanItemVm2()); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
DataContext = new TestVm();
}
}
}
Если вы запускаете код в эмуляторе, а затем переключаетесь на Item2 в Panorama. Через 5 секунд он вернется на страницу с пометкой "Управление".
В этом тестовом коде я могу обойти проблему одним из следующих способов: а) изменить панель StackPanel, в которой содержится ProgressIndicator, на сетку; б) удалить ProgressIndicator.
Однако ни одно из этих решений не подходит для моего правильного проекта, но если я удаляю код Visibility, который использует BooleanToVisibilityConverter, он не возвращается назад.
У кого-нибудь есть идеи, что может быть причиной этого? Я могу опубликовать весь пример кода, если это полезно.
Спасибо
--- РЕДАКТИРОВАТЬ ---
Вот код для BooleanToVisibilityConverter
using System.Windows;
using System.Windows.Data;
namespace Wp8.Gui.Converters
{
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is bool)
{
bool visibilityValue = true;
if(parameter != null)
{
if(parameter is string)
{
bool.TryParse((string)parameter, out visibilityValue);
}
}
return (bool)value == visibilityValue ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Visible;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
}
1 ответ
У меня была такая же проблема. У меня есть Панорама (измененная для заполнения на весь экран), которую я использую для отображения изображений в карусели. Я должен включить / выключить снимки в зависимости от положения панорамы, чтобы память оставалась низкой. Однако всякий раз, когда изображение загружается, панорама возвращается к элементу по умолчанию... первому элементу.
Поэтому я взял подсказку из другого вопроса и пошел смотреть исходный код Panorama. Хотя вы не можете видеть текущий код, вы можете видеть, какой была Panorama, когда она была частью WP Toolkit. Кажется, что когда бы ни происходило изменение размера панорамы, внутренний scrollviewer сбрасывается.
void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
// clip to control layout
LayoutRoot.SetValue(Panel.ClipProperty, new RectangleGeometry() { Rect = new Rect(0, 0, this.Width, this.Height) });
// reset scroll viewer
Dispatcher.BeginInvoke(() =>
{
ScrollView.Invalidate(false);
});
}
ХОРОШО. Это была подсказка. Поэтому я поигрался с моим itemtemplate (мой заголовок не существует), пытаясь увидеть, что меняло размер. Что-то меняло размер... не уверен что. Поэтому я обернул все в Grid и жестко закодировал Width/Height/MaxWidth/MaxHeight, чтобы он был равен Screen Height/Width. Они привязаны к вычисленным значениям в моей модели представления, которые меняются в зависимости от ориентации устройства.
<controls:PanoramaFullScreen.ItemTemplate>
<DataTemplate>
<Grid Width="{Binding LayoutWidth}"
MaxWidth="{Binding LayoutWidth}"
Height="{Binding LayoutHeight}"
MaxHeight="{Binding LayoutHeight}">
{rest of stuff}
</Grid>
</DataTemplate>
Оно работает! Больше не нужно переключаться на первый пункт!
Поэтому я подозреваю, что ваш код изменяет общую высоту / ширину объекта PanoramaItem, который, в свою очередь, изменяет размер Panorama и сбрасывает внутренний просмотрщик прокрутки.