如何访问 XAML DataTemplate 中的控件?控件、XAML、DataTemplate

2023-09-06 05:38:08 作者:江山杯中晃

我有这个翻转视图:

<FlipView x:Name="models_list" SelectionChanged="selectionChanged">
 <FlipView.ItemTemplate>
          <DataTemplate>
                <Grid x:Name="cv">
                        <Image x:Name="img1" Source = "{Binding ModelImage}" Stretch="Fill" Tag="{Binding ModelTag}"/>
                </Grid>
           </DataTemplate>
  </FlipView.ItemTemplate>

我想找到当前选定索引的 img1.在搜索它时,我在这里的一些帖子上找到了这种方法:

I want to find img1 of currently selected index. While searching for it I found this method on some post here:

private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
    {
        int childNumber = VisualTreeHelper.GetChildrenCount(control);
        for (int i = 0; i < childNumber; i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(control, i);
            FrameworkElement fe = child as FrameworkElement;
            // Not a framework element or is null
            if (fe == null) return null;

            if (child is T && fe.Name== ctrlName)
            {
                // Found the control so return
                return child;
            }
            else
            {
                // Not found it - search children
                DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
                if (nextLevel != null)
                    return nextLevel;
            }
        }
        return null;
    }

它返回给我 Flipview 的第一个索引上的图像,但我需要当前选定索引上的图像.我尝试编辑此方法,但找不到所需的控件.谁能帮帮我?

It returns me the Image on the first index of flipview but I need the one present on the currently selected index.. I tried to edit this method but I am unable to find the required control. Can anyone help me?

推荐答案

你遇到的问题是DataTemplate在重复,内容是由FlipView.Name 未公开,因为它会与生成的前一个兄弟(或将要生成的下一个)冲突.

The problem you are experiencing is that the DataTemplate is repeating and the content is being generated by the FlipView. The Name is not exposed because it would conflict with the previous sibling that was generated (or the next one that will be).

因此,要在 DataTemplate 中获取命名元素,您必须首先获取生成的项目,然后在生成的项目中搜索所需的元素.请记住,XAML 中的逻辑树是您按名称访问事物的方式.生成的项目不在逻辑树中.相反,它们位于可视树中(所有控件都位于可视树中).这意味着您必须在可视树中搜索要引用的控件.VisualTreeHelper 让您可以做到这一点.

So, to get a named element in the DataTemplate you have to first get the generated item, and then search inside that generated item for the element you want. Remember, the Logical Tree in XAML is how you access things by name. Generated items are not in the Logical Tree. Instead, they are in the Visual Tree (all controls are in the Visual Tree). That means it is in the Visual Tree you must search for the control you want to reference. The VisualTreeHelper lets you do this.

现在,该怎么做?

我为此写了一篇文章,因为这是一个反复出现的问题:http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html 但解决方案的核心是递归看起来像这样的方法:

I wrote an article on this because it is such a recurring question: http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html but the meat of the solution is a recursive method that looks something like this:

public void TestFirstName()
{
    foreach (var item in MyFlipView.Items)
    {
        var _Container = MyFlipView.ItemContainerGenerator
            .ContainerFromItem(item);
        var _Children = AllChildren(_Container);

        var _FirstName = _Children
            // only interested in TextBoxes
            .OfType<TextBox>()
            // only interested in FirstName
            .First(x => x.Name.Equals("FirstName"));

        // test & set color
        _FirstName.Background = 
            (string.IsNullOrWhiteSpace(_FirstName.Text))
            ? new SolidColorBrush(Colors.Red)
            : new SolidColorBrush(Colors.White);
    }
}

public List<Control> AllChildren(DependencyObject parent)
{
    var _List = new List<Control>();
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        var _Child = VisualTreeHelper.GetChild(parent, i);
        if (_Child is Control)
            _List.Add(_Child as Control);
        _List.AddRange(AllChildren(_Child));
    }
    return _List;
}

这里的关键问题是像这样的方法获取所有子控件,然后在生成的子控件列表中,您可以搜索所需的特定控件.有意义吗?

The key issue here is that a method like this gets all the children, and then in the resulting list of child controls you can search for the specific control you want. Make sense?

现在回答你的问题!

因为你特别想要当前选中的项目,你可以像这样简单地更新代码:

Because you specifically want the currently selected item, you can simply update the code like this:

if (MyFlipView.SelectedItem == null)
    return;
var _Container = MyFlipView.ItemContainerGenerator
    .ContainerFromItem(MyFlipView.SelectedItem);
// then the same as above...