将共享浮出控件绑定到 UWP 中 Listview 的 DataTemplate 中的 2 个控件 Windows 10

Binding shared flyout to 2 controls in Listview's DataTemplate in UWP Windows 10

我在 <Page.Resources> 中定义了一个共享 Flyout,如下所示:

<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 错误,所以我使用了这篇文章 (Using Windows 8.1 Flyout control with 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 或按下 [=31] 中的按钮时打开=]:

<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 "attached" 到 Grid

FlyoutBase.AttachedFlyout="{StaticResource InfoFlyout}"

我通过以下方式将相同的 Flyout 附加到 ListViewItem 本身的按钮:

Flyout="{StaticResource InfoFlyout}"

我已经为 IsOpen 属性 在我的 setter 和 getter 上设置了断点,当页面加载时,它会进入 getter 但每当我通过 Holding 或按下 'i' 按钮打开或关闭我的 Flyout,它不会触发下面的方法,因此它不会更改 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 无论用户将 his/her 手指放在相关 ListViewItem 而不是在实际 ListViewItem?

之上或之下

我知道这与最初的问题有点不同,最初的问题是通过控件共享弹出按钮,但最好还是完成它,因为它与问题有某种相关性。

谢谢。

通过 Using Windows 8.1 Flyout control with MVVM ,作者使用 parent 来控制弹出窗口的显示位置。 所以作者有如下代码(FlyoutHelpers.cs):

private static void OnIsOpenPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var flyout = d as Flyout;
        var parent = (ListView)d.GetValue(ParentProperty);

        if (flyout != null && parent != null)
        {
            var newValue = (bool)e.NewValue;

            if (newValue)
              flyout.ShowAt(parent);
            else
              flyout.Hide();
        }
    }

他使用 flyout.ShowAt(parent) 让弹出窗口显示在父元素上。但是在您的代码中,您已使用以下方法将弹出窗口绑定到按钮:

<Button Width="30" Height="30"
        Flyout="{StaticResource InfoFlyout}" content="i">
</Button>

所以没有必要再让它显示在它的父节点上。要解决此问题,您可以注释掉如下语句:

private static void OnIsOpenPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        //var flyout = d as Flyout;
        //var parent = (ListView)d.GetValue(ParentProperty);

        //if (flyout != null && parent != null)
        //{
        //    var newValue = (bool)e.NewValue;

        //    if (newValue)
        //      flyout.ShowAt(parent);
        //    else
        //      flyout.Hide();
        //}
    }

然后您将在正确的位置看到弹出显示。

将 Parent 的类型从 Button 更改为 ListView。在 WP 中无法打开特别是 X、Y 位置的弹出窗口。您可以改为选择 PopUp 控件。这是我 open the pop up in tapped position 得到的 link。您可以使用 VisualTreeHelper 获取点击的 ListViewItem

的 PopUp 控件