-->

如何访问一个XAML的DataTemplate内的控制?(How do I access a con

2019-09-01 23:07发布

我有这个flipview:

<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。 虽然寻找它,我发现这里上一些后此方法:

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的第一个索引图像,但我需要对当前选定的指数中所存在..我试图修改这个方法,但我无法找到所需要的控制。 谁能帮我?

Answer 1:

您所遇到的问题是, DataTemplate被重复,并且由生成的内容FlipView 。 该Name不被暴露,因为它将与已生成的上一个兄弟(或下一个将要)发生冲突。

因此,要在一个名为元素DataTemplate你必须首先获取生成项目,然后为你想要的元素生成项目内进行搜索。 请记住,在XAML逻辑树是如何通过名称访问的事情。 生成的项目不按逻辑树。 相反,它们是在视觉树(所有的控制都是在可视化树)。 这意味着它是在Visual树,你必须寻找你要引用的控制。 该VisualTreeHelper可以让你做到这一点。

现在,该怎么办呢?

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

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;
}

这里的关键问题是,这样的方法得到所有的孩子,然后在出现的孩子的列表控件,您可以搜索您需要的特定控制。 合理?

现在回答你的问题!

因为你特别希望当前选定的项目,你可以简单地更新这样的代码:

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


Answer 2:

也许有点更通用的方法可能是这样的:

private 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;
 } 


private T FindControl<T> (DependencyObject parentContainer, string controlName)
{            
        var childControls = AllChildren(parentContainer);
        var control = childControls.OfType<Control>().Where(x => x.Name.Equals(controlName)).Cast<T>().First();           
        return control;
}

你会调用的FindControl这样的:

var parentContainer = this.flipView.ItemContainerGenerator.ContainerFromItem(this.flipView.SelectedItem);
var myImage = FindControl<Image>(parentContainer, "img1");

//suppose you want to change the visibility
myImage.Visibility = Windows.UI.Xaml.Visibility.Collapsed;         


Answer 3:

简单的解决方案,以获得到一个DataTemplate中的元素访问包裹的DataTemplate的内容的用户控件,在那里你可以访问在一个ItemsControl的项目的所有UI元素。 我认为FlipView通常虚拟化的项目,因此,即使你有100个项目绑定了 - 只有2-3实际上可能在UI当前表示(其中隐藏的1-2),所以你必须要记住,当你想更换任何东西,当一个项目被装载到控制实际上只进行更改。

如果你真的需要确定代表的ItemsSource该项目的项目容器-你可以检查你的FlipView的ItemContainerGenerator属性及其ContainerFromItem()方法。

为了让你可以使用一个项目的坐标GetBoundingRect()中的WinRT XAML工具箱扩展方法。

不过总的来说,根据您的评论可能是最好的办法其实是完全不同的。 如果您在您的FlipView绑定到一个源 - 通常可以控制通过更改绑定的源集合项的属性显示或重叠的图像。



Answer 4:

如果你只是想在项目点击屏幕坐标...你可以注册在图像上单击处理程序,然后使用senderimg.transform tovisual(空),这给你一个generaltransforn从中你可以获得当前点坐标。



Answer 5:

我挣扎这丝毫整天,似乎控制是为了得到它的子控件从的DataTemplate来加载(渲染)。 这意味着你不能使用上载窗口此代码或任何代码(用于同样目的),初始化...您如何以往任何时候都使用它的控制,例如在初始化的SelectedItem后。

我建议使用转换器和定义的,而不是直接控制访问的转换器所请求的动作。



Answer 6:

所以,如果你通过结合分配资源,为什么你会不会做同样的休息: <FlipView SelectedIndex="{Binding SIndex}" SelectedItem="{Binding SItem}" SelectedValue="{Binding SValue}"/>

您必须先为这个特性准备到位。 它可以是从派生的类INotifyPropertyChanged

聘请MVVM为你工作,做最XAML。 当然,在开始时它似乎是更多的工作,但更复杂的项目,MVVM将是连贯和灵活。



文章来源: How do I access a control inside a XAML DataTemplate?