本帖最后由 df4rtv4t 于 2015-02-07 09:53:14 编辑

解决方案 »

  1.   


    没有了Name,程序找不到对像了。
      

  2.   

    nono,PART_ContentHost 是专属名词, 就像 DocumentViewer控件,它也有这个命名。 个人觉得  这也就是为什么会有TemplateBinding 的原因,你可以binding它的Width与Height 属性,但是不需要 任何x:name  ,但是ScrollViewer就需要。如果会使用blend工具的话,可以编辑一个控件的副本,会发现有很多以 PART开头的名词。
      

  3.   

    我们知道WPF控件是不用有固定形状的,我们可以通过Style来任意改变它的具体表现。
    但是,控件本身具有特定的逻辑和作用,比如一个按钮,应该是可以点击的;一个颜色选择控件,应该是可以用来选颜色的。
    这里就存在了一个矛盾:如果可以任意改变控件的具体表现,那么如何保证它特有的逻辑和作用呢?答案就是WPF控件的‘部件’概念。简单的说,就是你可以任意改变我,但是要提供我期待的部件,否则我的逻辑和作用就不能得到保证。如果阅读TextBoxBase的MSDN参考(TextBox继承于TextBoxBase),你会看到如下的特性:
    该特性表明TextBoxBase控件期待你提供一个名字叫PART_ContentHost的部件,该部件必须是FrameworkElement。而TextBoxBase将会把具体的TextView和TextEditor放到PART_ContentHost里面。
      

  4.   

    这里我用代码解释WPF控件中‘部件’的使用。1、新建一个WPF自定义控件项目,并取名为MyUpDown。
    2、把CustomControl1(包括文件等)换名为MyUpDown。
    3、把Generic.xaml和MyUpDown.cs内容换成:<ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyUpDown">
        <Style TargetType="{x:Type local:MyUpDown}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:MyUpDown">
                        <StackPanel Margin="3" Orientation="Horizontal" Background="{TemplateBinding Background}">
                            <TextBlock Width="30" VerticalAlignment="Center"
                                       Text="{Binding Path=Value, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MyUpDown}}}" />
                            <RepeatButton Width="40" Content="Up"  Name="PART_UpButton" />
                            <RepeatButton Width="40" Content="Down" Name="PART_DownButton" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>[TemplatePart(Name = "PART_UpButton", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "PART_DownButton", Type = typeof(ButtonBase))]
    public partial class MyUpDown : Control
    {
        static MyUpDown()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyUpDown), new FrameworkPropertyMetadata(typeof(MyUpDown)));
        }    public override void OnApplyTemplate()
        {
            UpButton = GetTemplateChild("PART_UpButton") as ButtonBase;
            DownButton = GetTemplateChild("PART_DownButton") as ButtonBase;
        }    ButtonBase upButton;
        ButtonBase UpButton
        {
            get { return this.upButton; }
            set
            {
                if (this.upButton != null) this.upButton.Click -= Button_Click;
                this.upButton = value;
                if (this.upButton != null) this.upButton.Click += Button_Click;
            }
        }    ButtonBase downButton;
        ButtonBase DownButton
        {
            get { return this.downButton; }
            set
            {
                if (this.downButton != null) this.downButton.Click -= Button_Click;
                this.downButton = value;
                if (this.downButton != null) this.downButton.Click += Button_Click;
            }
        }    void Button_Click(object sender, RoutedEventArgs e)
        {
            if (object.ReferenceEquals(sender, this.upButton)) this.Value++;
            if (object.ReferenceEquals(sender, this.downButton)) this.Value--;
        }    public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(MyUpDown));
    }4、确保编译成功(控件本身不能运行)。
    5、新建一个WPF窗口项目,并添加对MyUpDown项目的引用。
    6、从工具栏中,拖一个MyUpDown控件到窗口中,编译运行就可以看到一个类似NumericUpDown的控件。点击Up和Down按钮,可以看到数字的相应变化。下面,我们来自定义(假设是别人提供的)MyUpDown控件:
    <Grid>
        <MyUpDown:MyUpDown Value="123" >
            <MyUpDown:MyUpDown.Template>
                <ControlTemplate TargetType="MyUpDown:MyUpDown">
                    <Grid>
                        <TextBox Text="{Binding Path=Value,RelativeSource={RelativeSource AncestorType=MyUpDown:MyUpDown}}" Width="150" Height="30" />
                        <Button Content="UpOnly" Width="50" Height="30" Margin="200 0 0 0" />
                    </Grid>
                </ControlTemplate>
            </MyUpDown:MyUpDown.Template>
        </MyUpDown:MyUpDown>
    </Grid>
    在新的模板中,我们用TextBox来支持直接编辑,同时提供一个按键。编译运行,可以发现MyUpDown可以显示Value的数值,但是,两个按钮不见了,我们提供的UpOnly按钮不起作用。这就是我们没有按照控件期待提供特定名字按钮的结果。现在,把Button的代码更改为:
    <Button Content="UpOnly" Width="50" Height="30" Margin="200 0 0 0" Name="PART_UpButton" />
    编译运行,可以发现只有一个按钮,但该UpOnly按钮可以向上调整数字了。用代码上看,MyUpDown.cs第10行中,当开始应用模板OnApplyTemplate的时候,MyUpDown控件尝试着寻找两个特定名字类型为按钮的部件:
    GetTemplateChild("PART_UpButton") as ButtonBase;
    ...
    如果找到按钮部件,则为按钮添加单击事件的响应函数,并在响应函数中相应地对当前数字进行加一或减一,从而达到用按钮调整数字的特定作用(NumericalUpDown)。如果找不到部件,WPF控件可以根据严重程度,选择抛出异常,或减少功能等措施。