UWP:从 FlyoutMenuItem 单击处理程序中查找父级
UWP: find parent from FlyoutMenuItem click handler
使用 UWP,我有一个 ListView
,其中每个项目都包含一个 Button
。点击按钮打开 MenuFlyout
。点击弹出选项之一会触发 Click
事件。
在事件处理程序中,如何找到父 Button 或父 ListView
项?
这是我的 XAML 的摘录。具体来说,我想在 OnItemEdit
处理程序中找到“Note”元素。
<Page.Resources>
<ResourceDictionary>
<DataTemplate x:Key="NoteItemTemplate">
<Grid>
<Grid.ColumnDefinitions> ... </Grid.ColumnDefinitions>
<TextBox Name="Note" />
<Button>
<Image Source="..." />
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem Text="Edit" Click="OnItemEdit" />
<MenuFlyoutItem Text="Delete" Click="OnItemDelete" />
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
</DataTemplate>
...
<local:DetailItemSelector x:Key="DetailItemSelector"
NoteItemTemplate="{StaticResource NoteItemTemplate}"
...
/>
</ResourceDictionary>
</Page.Resources>
<ListView
x:Name = "DetailList"
ItemsSource = "{x:Bind DetailListItems}"
ItemTemplateSelector = "{StaticResource DetailItemSelector}">
</ListView>
处理程序定义为:
async void OnItemEdit(object sender, RoutedEventArgs e)
{
...
}
编辑 - 解决方法
如果没有更好的方法,这里有一个还不错的解决方法。诀窍是使用 FlyoutBase.AttachedFlyout
而不是 Button.Flyout
.
<DataTemplate x:Key="NoteItemTemplate">
<Grid>
<Grid.ColumnDefinitions> ... </Grid.ColumnDefinitions>
<TextBox ... Name="Note" />
<Button ... Click=="onMoreClicked">
<Image Source="..." />
FlyoutBase.AttachedFlyout
<MenuFlyout>
<MenuFlyoutItem Text="Edit" Click="OnItemEdit" />
<MenuFlyoutItem ... />
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
</Button>
</Grid>
</DataTemplate>
还有,代码隐藏
FrameworkElement lastItemTapped = null;
public void onMoreClicked (object sender, RoutedEventArgs e)
{
Button button = sender as Button;
// find parent list item containing button
DependencyObject element = button;
while (element != null)
{
if (element is FrameworkElement && (element as FrameworkElement).Name.Equals("Item"))
break;
element = VisualTreeHelper.GetParent(element);
}
if (element != null)
lastItemTapped = element as FrameworkElement;
// show flyout menu
FlyoutBase.ShowAttachedFlyout(button);
}
public void OnItemEdit(object sender, RoutedEventArgs e)
{
if (lastItemTapped == null)
return;
...
}
在您的方案中,您可以添加一个成员变量来保存代表 ListViewItem
的 Grid
实例以供以后访问。将 PointerEntered
事件添加到 Grid
面板。当您单击某个项目的按钮弹出弹出窗口时,将首先触发该项目的 Grid
的 PointerEntered
事件处理程序。在 PointerEntered
事件处理程序中,将 sender
分配给成员变量。然后您可以在 OnItemEdit
事件处理程序中访问 Grid
。
您可以检查以下内容作为示例:
//MainPage.xaml
<DataTemplate x:Key="NoteItemTemplate">
<Grid PointerEntered="Grid_PointerEntered" >
<Grid.ColumnDefinitions> ... </Grid.ColumnDefinitions>
……
</Grid>
</DataTemplate>
//MainPage.xaml.cs
private Grid myPanel;
private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e)
{
myPanel = sender as Grid;
}
private void OnItemEdit(object sender, RoutedEventArgs e)
{
//Change the value of index to adjust your scenario
var box = VisualTreeHelper.GetChild(myPanel, 0) as TextBox;
}
更新:
请尝试以下代码:
private void OnItemEdit(object sender, RoutedEventArgs e)
{
//Find the item be clicked
object clickedItem=new object();
foreach(var cur in DetailList.Items)
{
if(cur.ToString()==(sender as MenuFlyoutItem).DataContext.ToString())
{
clickedItem = cur;
break;
}
}
//
var type = DetailList.ContainerFromItem(clickedItem);
var item = type as ListViewItem;
var box = VisualTreeHelper.GetChild(item.ContentTemplateRoot as DependencyObject, 0);
string text = (box as TextBox).Text;
}
Specifically, I want to find the "Note" element while in the the OnItemEdit handler.
假设 DataTemplate
应用于“注释”,这应该像将 sender
参数的 DataContext
转换为 Note
一样简单(或不管你叫什么类型):
private void OnItemEdit(object sender, RoutedEventArgs e)
{
MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
var note = menuFlyoutItem.DataContext as YourNoteClass;
...
}
如果您需要对“节点”TextBox
元素的引用,您可以在可视化树中找到它:
private void OnItemEdit(object sender, RoutedEventArgs e)
{
MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
DependencyObject container = DetailList.ContainerFromItem(menuFlyoutItem.DataContext);
TextBox note = FindVisualChild<TextBox>(container);
...
}
private static T FindVisualChild<T>(DependencyObject visual) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(visual, i);
if (child != null)
{
T correctlyTyped = child as T;
if (correctlyTyped != null)
return correctlyTyped;
T descendent = FindVisualChild<T>(child);
if (descendent != null)
return descendent;
}
}
return null;
}
使用 UWP,我有一个 ListView
,其中每个项目都包含一个 Button
。点击按钮打开 MenuFlyout
。点击弹出选项之一会触发 Click
事件。
在事件处理程序中,如何找到父 Button 或父 ListView
项?
这是我的 XAML 的摘录。具体来说,我想在 OnItemEdit
处理程序中找到“Note”元素。
<Page.Resources>
<ResourceDictionary>
<DataTemplate x:Key="NoteItemTemplate">
<Grid>
<Grid.ColumnDefinitions> ... </Grid.ColumnDefinitions>
<TextBox Name="Note" />
<Button>
<Image Source="..." />
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem Text="Edit" Click="OnItemEdit" />
<MenuFlyoutItem Text="Delete" Click="OnItemDelete" />
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
</DataTemplate>
...
<local:DetailItemSelector x:Key="DetailItemSelector"
NoteItemTemplate="{StaticResource NoteItemTemplate}"
...
/>
</ResourceDictionary>
</Page.Resources>
<ListView
x:Name = "DetailList"
ItemsSource = "{x:Bind DetailListItems}"
ItemTemplateSelector = "{StaticResource DetailItemSelector}">
</ListView>
处理程序定义为:
async void OnItemEdit(object sender, RoutedEventArgs e)
{
...
}
编辑 - 解决方法
如果没有更好的方法,这里有一个还不错的解决方法。诀窍是使用 FlyoutBase.AttachedFlyout
而不是 Button.Flyout
.
<DataTemplate x:Key="NoteItemTemplate">
<Grid>
<Grid.ColumnDefinitions> ... </Grid.ColumnDefinitions>
<TextBox ... Name="Note" />
<Button ... Click=="onMoreClicked">
<Image Source="..." />
FlyoutBase.AttachedFlyout
<MenuFlyout>
<MenuFlyoutItem Text="Edit" Click="OnItemEdit" />
<MenuFlyoutItem ... />
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
</Button>
</Grid>
</DataTemplate>
还有,代码隐藏
FrameworkElement lastItemTapped = null;
public void onMoreClicked (object sender, RoutedEventArgs e)
{
Button button = sender as Button;
// find parent list item containing button
DependencyObject element = button;
while (element != null)
{
if (element is FrameworkElement && (element as FrameworkElement).Name.Equals("Item"))
break;
element = VisualTreeHelper.GetParent(element);
}
if (element != null)
lastItemTapped = element as FrameworkElement;
// show flyout menu
FlyoutBase.ShowAttachedFlyout(button);
}
public void OnItemEdit(object sender, RoutedEventArgs e)
{
if (lastItemTapped == null)
return;
...
}
在您的方案中,您可以添加一个成员变量来保存代表 ListViewItem
的 Grid
实例以供以后访问。将 PointerEntered
事件添加到 Grid
面板。当您单击某个项目的按钮弹出弹出窗口时,将首先触发该项目的 Grid
的 PointerEntered
事件处理程序。在 PointerEntered
事件处理程序中,将 sender
分配给成员变量。然后您可以在 OnItemEdit
事件处理程序中访问 Grid
。
您可以检查以下内容作为示例:
//MainPage.xaml
<DataTemplate x:Key="NoteItemTemplate">
<Grid PointerEntered="Grid_PointerEntered" >
<Grid.ColumnDefinitions> ... </Grid.ColumnDefinitions>
……
</Grid>
</DataTemplate>
//MainPage.xaml.cs
private Grid myPanel;
private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e)
{
myPanel = sender as Grid;
}
private void OnItemEdit(object sender, RoutedEventArgs e)
{
//Change the value of index to adjust your scenario
var box = VisualTreeHelper.GetChild(myPanel, 0) as TextBox;
}
更新:
请尝试以下代码:
private void OnItemEdit(object sender, RoutedEventArgs e)
{
//Find the item be clicked
object clickedItem=new object();
foreach(var cur in DetailList.Items)
{
if(cur.ToString()==(sender as MenuFlyoutItem).DataContext.ToString())
{
clickedItem = cur;
break;
}
}
//
var type = DetailList.ContainerFromItem(clickedItem);
var item = type as ListViewItem;
var box = VisualTreeHelper.GetChild(item.ContentTemplateRoot as DependencyObject, 0);
string text = (box as TextBox).Text;
}
Specifically, I want to find the "Note" element while in the the OnItemEdit handler.
假设 DataTemplate
应用于“注释”,这应该像将 sender
参数的 DataContext
转换为 Note
一样简单(或不管你叫什么类型):
private void OnItemEdit(object sender, RoutedEventArgs e)
{
MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
var note = menuFlyoutItem.DataContext as YourNoteClass;
...
}
如果您需要对“节点”TextBox
元素的引用,您可以在可视化树中找到它:
private void OnItemEdit(object sender, RoutedEventArgs e)
{
MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
DependencyObject container = DetailList.ContainerFromItem(menuFlyoutItem.DataContext);
TextBox note = FindVisualChild<TextBox>(container);
...
}
private static T FindVisualChild<T>(DependencyObject visual) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(visual, i);
if (child != null)
{
T correctlyTyped = child as T;
if (correctlyTyped != null)
return correctlyTyped;
T descendent = FindVisualChild<T>(child);
if (descendent != null)
return descendent;
}
}
return null;
}