我也是WPF的新手~
我看你这代码的意思,不应该是在CustomControl的内容里面嵌入了一个宽度为2的UserControl吗??

解决方案 »

  1.   

    我就是这个意思啊,可是,为什么UserControl的宽度就不是2呢?
      

  2.   

    WPF对依赖属性值的读取是有优先级控制的,由先到后依次是:(1)WPF属性系统强制值。(2)由动画过程控制的值。(3)本地变量值(存储在EffectiveValueEntry数组中)。(4)由上级元素的Template设置的值。(5)由隐式样式(Implicit Style)设置的值。(6)由样式之触发器(Style Trigger)设置的值。(7)由模板之触发器(Template Trigger)设置的值。(8)由样式之设置器(Style Setter)设置的值。(9)由默认样式(Default Style)设置的值,默认模式其实就是由主题(Theme)指定的模式。(10)由上级元素继承而来的值。(11)默认值,来源于依赖属性的元数据(metadata)。
      

  3.   

    <Window x:Class="WPF3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WPF3"
            Title="MainWindow" Height="350" Width="525">
       <Grid>
          <local:UserControl1 Width="2"/>
        </Grid>
    </Window>那为什么,在主窗体中设置的UserControl1的Width值又有效呢?
      

  4.   

    等于2的处理是在InitializeComponent()里执行了,之后又执行了this.Width = 100;所以等于2就不好使了。在调试构造函数时,里面的属性是在构造函数执行完了以后才起作用的,所以,在构造函数里设断点作用不大,你可以试试把this.Width = 100;去掉看看。
      

  5.   

    等于2的处理是在InitializeComponent()里执行了?等于2是在CustomControl1的样式中设置的啊,又不是在UserControl1的XAML中设置的。好吧,UserControl1的InitializeComponent方法加载的应该是UserControl1的XAML吧。
    好吧,如果如你所说的话,看下面的代码:
    <Window x:Class="WPF3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WPF3"
            Title="MainWindow" Height="350" Width="525">
       <Grid>
            <StackPanel>
                <local:CustomControl1/>
                <local:UserControl1 Width="2"/>
            </StackPanel>
        </Grid>
    </Window>同样是在XMAL中设置UserControl1的Width为2,这个就有效,而在CustomControl1的XAML中设置UserControl1的Width为2就没有效果,这是为什么呢?
      

  6.   

    首先要明确的概念是:Template不是具体的控件,而只是一个模板(用同一个模板可以生产多个具体的控件)。
    因此对模板的属性设置,并没有直接设置到具体的控件上。要解释这点,可以把你Xaml中有关Template的部分,换成代码实现:FrameworkElementFactory borderFactory = new FrameworkElementFactory(typeof(Border));  // <Border>
    FrameworkElementFactory userControl1Factory = new FrameworkElementFactory(typeof(UserControl1)); // <local:UserControl
    userControl1Factory.SetValue(UserControl1.WidthProperty, 2.0); // Width="2" />
    borderFactory.AppendChild(userControl1Factory);ControlTemplate customControl1Template = new ControlTemplate(typeof(CustomControl1));
    customControl1Template.VisualTree = borderFactory;
    //...可以看到,当你写<local:UserControl1 Width="2"/>的时候,属性并不是直接设置到UserControl1上的,而是设置到一个FrameworkElementFactory的工厂上。当WPF运行中对控件施用模板时,工厂再
    1、创建具体的控件实例
    2、并把工厂中的模板属性值,应用到实例去。这里说的应用模板属性,就会有优先级的考虑,很可能这种模板属性的优先级比‘本地值’低(在构造函数里直接设置的算本地值)。
    这个可以解释为什么,在构造函数中设置的宽度高度(本地值),不会被模板中的数值覆盖。相反,如果在StackPanel中直接实例化UserControl1,并设置宽度。那么该设置是‘本地值’,可以生效。
      

  7.   

    还是不太理解。我有新建了一个UserControl2:<UserControl x:Class="WPF3.UserControl2"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/up-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:WPF3"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <local:UserControl1 Width="2"/>
        </Grid>
    </UserControl>同样使用了UserControl1 ,并把Width设为2,但是却是有效果的。<Window x:Class="WPF3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WPF3"
            Title="MainWindow" Height="350" Width="525">
       <Grid>
            <StackPanel>
                <local:CustomControl1/>
                <local:UserControl2/>
            </StackPanel>
        </Grid>
    </Window>这又是为什么呢?
      

  8.   

    同样,就算是用个样式,也没有效果:<Window x:Class="WPF3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WPF3"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <Style x:Key="aa" TargetType="Control">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border>
                                <local:UserControl1 Width="2"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Resources>
       <Grid>
            <StackPanel>
                <Control Style="{StaticResource aa}"/>
                <local:UserControl2/>
            </StackPanel>
        </Grid>
    </Window>
      

  9.   

    问你自己如下问题:
    1、12楼中的UserControl2和UserControl1是通过模板创建出来的吗?你看到类似Template的语句了吗?
    2、13楼的<Control Style="{StaticResource aa}"/>,是否通过模板来自定义Control?Style里面的UserControl1是不是ControlTemplate的一部分?
      

  10.   

    不是通过模板创建的。不过,我查了下9楼的FrameworkElementFactory类:MSDN
    这是一个弃用的类呢。
    我在MSDN、网上搜索了一下阁下所说的用“工厂”创建控件,以及此时的优先级。都没有这方面的资料。我想学得更多一点、更扎实点这方面的知识块。
      

  11.   

    之所以弃用,是因为它不能完成Xaml的所有功能。但是不妨碍我们用代码去理解xaml中模板的实现。下面的例子给出三种模板(可以用鼠标点击来轮换):
    1、没有模板
    2、使用代码创建模板(用‘弃用’的FrameworkElementFactory)
    3、使用载入Xmal的方式创建模板(所谓‘正确’的创建方式)例子要说明的是:
    1、Xmal的Template如果用代码创建,如何表达
    2、在代码表达中,可以清楚地看到,模板中的‘元素’实际上都是‘元素工厂’(Xaml模板中看不出来)。
    3、在代码表达中,属性的设置,实际上是先设置到‘‘元素工厂’上。
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <StackPanel>
            <Control Name="myControl" />
        </StackPanel>
    </Window>using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Markup;
    using System.Windows.Media;namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();            this.Title = "鼠标点击,显示几种模板的效果[无,代码模板,xaml模板]";
                ControlTemplate[] templates = { null, CreateTemplateCode(), CreateTemplateXaml() };
                int i = 0;
                this.MouseDown += delegate { myControl.Template = templates[++i % templates.Length];};
            }        ControlTemplate CreateTemplateCode()
            {
                var borderFactory = new FrameworkElementFactory(typeof(Border));  // <Border>
                var userControl1Factory = new FrameworkElementFactory(typeof(UserControl1)); // <local:UserControl1
                borderFactory.SetValue(Border.BackgroundProperty, Brushes.Yellow); // 代码方式额外改变Border的背景,以便区别
                userControl1Factory.SetValue(UserControl1.WidthProperty, 2.0); // Width="2" />
                borderFactory.AppendChild(userControl1Factory);            ControlTemplate controlTemplate = new ControlTemplate(typeof(Control));
                controlTemplate.VisualTree = borderFactory;            return controlTemplate;
            }        ControlTemplate CreateTemplateXaml()
            {
                string xaml = string.Format(
                    @"<ControlTemplate TargetType='Control' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                        <Border>
                            <local:UserControl1 Width='2' xmlns:local='clr-namespace:{0};assembly={1}'/>
                        </Border>
                    </ControlTemplate>",
                    typeof(UserControl1).Namespace,
                    typeof(UserControl1).Assembly.GetName().Name);            return (ControlTemplate)XamlReader.Parse(xaml);
            }
        }    // 可以不需要另外的UserControl1.xaml
        public class UserControl1 : UserControl
        {
            public UserControl1()
            {
                this.Background = Brushes.Red;
                this.Height = 100;
                this.Width = 100;
            }
        }
    }