深入浅出WPF-笔记(2015.04.18)

    ControlTemplate和DataTemplate两个类均派生自FrameworkTemplate类,这个类的FindName方法能检索其内部控件。示例如下:

XAML代码:

<Window x:Class="MyTestWpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyTestWpfApplication"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"       
        Title="WPF" Height="172" Width="300" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <ControlTemplate x:Key="cTmp">
            <StackPanel Background="Orange">
                <TextBox x:Name="textBox1" Margin="6"/>
                <TextBox x:Name="textBox2" Margin="6,0"/>
                <TextBox x:Name="textBox3" Margin="6"/>
            </StackPanel>
        </ControlTemplate>
    </Window.Resources>
    <StackPanel Background="Yellow">
        <UserControl x:Name="uc" Template="{StaticResource ResourceKey=cTmp}" Margin="5"/>
        <Button Content="Find By Name" Width="120" Height="30" Click="Button_Click"/>
    </StackPanel>
</Window>

 

C#代码:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TextBox tb = this.uc.Template.FindName("textBox1", this.uc) as TextBox;
            tb.Text = "Hello Wpf";
            StackPanel sp = tb.Parent as StackPanel;
            (sp.Children[1] as TextBox).Text = "Hello,ControlTemplate";
            (sp.Children[2] as TextBox).Text = "I can find you";
        }
    }

==============================================================================

     寻找到一个由DataTemplate生成的控件后,想从中获取哪些数据,如果想获得单纯与用户界面相关的数据,这么做是正确的;但如果是获取与业务逻辑相关的数据,就要考虑程序的设计是不是出了问题--因为WPF采用数据驱动UI逻辑,获取业务逻辑数据的事情在底层就能做到,一般不会跑到表层上来找。

XAML代码:

<Window x:Class="MyTestWpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyTestWpfApplication"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"       
        Title="WPF" Height="172" Width="300" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <local:Student x:Key="stu" Id="1" Name="Timothy" Skill="WPF" HasJob="True"/>
        <DataTemplate x:Key="stuDT">
            <Border BorderBrush="Orange" BorderThickness="2" CornerRadius="5">
                <StackPanel>
                    <TextBlock Text="{Binding Id}" Margin="5"/>
                    <TextBlock x:Name="textBlockName" Text="{Binding Name}" Margin="5"/>
                    <TextBlock Text="{Binding Skill}" Margin="5"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <ContentPresenter x:Name="cp" Content="{StaticResource ResourceKey=stu}" ContentTemplate="{StaticResource ResourceKey=stuDT}" Margin="5"/>
        <Button Content="Find" Margin="5,0" Click="Button_Click"/>
    </StackPanel>
</Window>

 

C#代码:

    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Skill { get; set; }
        public bool HasJob { get; set; }
    }

    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TextBlock tb = this.cp.ContentTemplate.FindName("textBlockName", this.cp) as TextBlock;
            MessageBox.Show(tb.Text);

            //Student stu = this.cp.Content as Student;
            //MessageBox.Show(stu.Name);
        }
    }

===============================================================================

    DataTemplate的一个常用之处是GridViewColumn的CellTemplate属性。把GridViewColumn放置GridView控件里就可以生成表格了。GridViewColumn的默认CellTemplate是使用TextBlock只读性地显示数据,如果想让用户能修改数据或使用CheckBox显示bool类型数据的话就需要自定义DataTemplate。示例如下:

XAML代码:

<Window x:Class="MyTestWpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyTestWpfApplication"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"       
        xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
        Title="WPF" Height="300" Width="300" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <c:ArrayList x:Key="stuList">
            <local:Student Id="1" Name="Timoty" Skill="WPF" HasJob="True"/>
            <local:Student Id="2" Name="Tom Change" Skill="BI/SQL" HasJob="True"/>
            <local:Student Id="3" Name="Guan Chong" Skill="Writing" HasJob="False"/>
            <local:Student Id="4" Name="Shanshan" Skill="C#/Java" HasJob="False"/>
            <local:Student Id="5" Name="Pingping Zhang" Skill="Writing" HasJob="False"/>
            <local:Student Id="6" Name="Kenny Tian" Skill="ASP.NET" HasJob="False"/>
        </c:ArrayList>
        <DataTemplate x:Key="nameDT">
            <TextBox x:Name="textBoxName" Text="{Binding Name}" GotFocus="TextBoxName_GotFocus"/>
        </DataTemplate>
        <DataTemplate x:Key="skillDT">
            <TextBox x:Name="textBoxSkill" Text="{Binding Skill}"/>
        </DataTemplate>
        <DataTemplate x:Key="hjDT">
            <CheckBox x:Name="checkBoxJob" IsChecked="{Binding HasJob}"/>
        </DataTemplate>
    </Window.Resources>
    <Grid Margin="5">
        <ListView x:Name="listViewStudent" ItemsSource="{StaticResource ResourceKey=stuList}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}"/>
                    <GridViewColumn Header="姓名" CellTemplate="{StaticResource ResourceKey=nameDT}"/>
                    <GridViewColumn Header="技术" CellTemplate="{StaticResource ResourceKey=skillDT}"/>
                    <GridViewColumn Header="已工作" CellTemplate="{StaticResource ResourceKey=hjDT}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

 

C#代码:

    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Skill { get; set; }
        public bool HasJob { get; set; }
    }

    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void TextBoxName_GotFocus(object sender, RoutedEventArgs e)
        {
            TextBox tb = e.OriginalSource as TextBox;
            ContentPresenter cp = tb.TemplatedParent as ContentPresenter;
            Student stu = cp.Content as Student;
            this.listViewStudent.SelectedItem = stu;

            ListViewItem lvi = this.listViewStudent.ItemContainerGenerator.ContainerFromItem(stu) as ListViewItem;
            CheckBox chb = this.FindVisualChild<CheckBox>(lvi);
            MessageBox.Show(chb.Name);
        }

        private ChildType FindVisualChild<ChildType>(DependencyObject obj) where ChildType : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); ++i)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (null != child && child is ChildType)
                    return child as ChildType;
                else
                {
                    ChildType childOfChild = FindVisualChild<ChildType>(child);
                    if (null != childOfChild)
                        return childOfChild;
                }
            }
            return null;
        }
    }

每个ItemControl的派生类都具有自己独特的容器,使用ItemContainGenerator.ContainerFromItem方法就能获得包装着指定条目数据的容器。 

你可能感兴趣的:(template,WPF)