У меня есть общий Flyout
, определенный в моем <Page.Resources>
следующим образом:
<Flyout x:Name="InfoFlyout" Opened="{Binding IsOpen,
ElementName=MyListView, Mode=TwoWay}">
<Grid>
<Button Foreground="White" Margin="5">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Help"/>
</StackPanel>
</Button>
</Grid>
</Flyout>
Но при компиляции получаю ошибку An object reference not set
, поэтому использовал код из этой статьи (Использование Windows 8.1 Flyout control с MVVM).
Кажется, это позволяет обойти проблему, с которой я столкнулся в приведенном выше коде. Теперь мой общий код Flyout
выглядит так:
<Flyout x:Name="InfoFlyout"
helpers:FlyoutHelpers.Parent="{Binding ElementName=MyListView}"
helpers:FlyoutHelpers.IsOpen="{Binding IsOpen, Mode=TwoWay}">
<Grid>
<Button Foreground="White" Margin="5">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Help"/>
</StackPanel>
</Button>
</Grid>
</Flyout>
Мой элемент управления ListView
(т.е. x:Name="MyListView") привязан к ViewModel
страницы, т.е. MainPageViewModel. Свойство IsOpen определено в MainViewModel.
Теперь в моем ListView
DataTemplate
я хочу, чтобы мой Flyout
открывался, когда я нажимаю и удерживаю ListViewItem
или при нажатии кнопки в ListViewItem
:
<DataTemplate>
<Grid FlyoutBase.AttachedFlyout="{StaticResource InfoFlyout}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source={Binding MyImage} />
<Grid Grid.Column="1" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Width="30" Height="30"
Flyout="{StaticResource InfoFlyout}"
content="i">
</Button>
</Grid>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Holding">
<actions:OpenFlyoutAction />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</Grid>
</DataTemplate>
Как видите, у меня есть Flyout
, "привязанный" к Grid
через:
FlyoutBase.AttachedFlyout="{StaticResource InfoFlyout}"
и у меня есть тот же Flyout
, прикрепленный к кнопке внутри самого ListViewItem
через:
Flyout="{StaticResource InfoFlyout}"
Я поставил точки останова как на мой установщик, так и на геттер для свойства IsOpen, и когда страница загружается, она переходит в геттер, но всякий раз, когда я открываю или закрываю свой Flyout
либо через Holding
, либо нажатием кнопки «i», это не t запускает описанный ниже метод и, следовательно, не изменяет свойство IsOpen.
private static void OnIsOpenPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e) as defined in the FlyoutHelper class.
Причина, по которой я установил свой ElementName
в MyListView, заключается в том, что я хочу, чтобы все мои ListViewItem
были привязаны к одному свойству, то есть IsOpen, поскольку мне нужно обнаруживать, когда открывается всплывающее меню, независимо от того, к какому ListViewItem
оно принадлежит.
Как я могу достичь или решить это?
ОБНОВЛЕНИЕ – 1
Проблема доступа к общему меню была решена с помощью следующего:
<Flyout x:Name="InfoFlyout"
helpers:FlyoutHelpers.Parent="{Binding ElementName=MyListView}"
helpers:FlyoutHelpers.IsOpen="{Binding IsOpen, Mode=TwoWay}">
и установка кнопки на
<Button Width="30" Height="30"
Command="{Binding InformationCommand}"
CommandParameter="{Binding}"
Flyout="{StaticResource InfoFlyout}">
Это нормально, и, как упомянул @ElvisXia, вы можете закомментировать код в OnIsOpenPropertyChanged, поскольку позиционирование уже определено кнопкой, расположенной внутри моего ListViewItem.
Однако есть одна нерешенная проблема. Кстати, небольшая, но хорошо, если ее можно решить. Общий всплывающий элемент, прикрепленный к самой сетке в DataTemplate, т.е.
<DataTemplate>
<Grid FlyoutBase.AttachedFlyout="{StaticResource InfoFlyout}">
Он позиционируется на основе ListViewItem, что технически правильно, поскольку я вызываю другой фрагмент кода для этого, т.е.
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Holding">
<actions:OpenFlyoutAction />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
И OpenFlyoutAction определяется следующим образом:
public class OpenFlyoutAction : DependencyObject, IAction
{
public object Execute(object sender, object parameter)
{
FrameworkElement senderElement = sender as FrameworkElement;
FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);
flyoutBase.ShowAt(senderElement);
return null;
}
}
Могу ли я каким-то образом перестать использовать OpenFlyoutAction
и использовать тот же код, что и в статье, чтобы открыть мой Flyout
везде, где пользователь держит палец на соответствующем ListViewItem
, а не над или под фактическим ListViewItem
?
Я понимаю, что это немного отходит от исходной проблемы, которая заключалась в том, чтобы поделиться всплывающим окном с элементами управления, но с таким же успехом можно закончить его, поскольку он каким-то образом имеет отношение к проблеме.
Спасибо.