将共享浮出控件绑定到 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 控件
我在 <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