代码之家  ›  专栏  ›  技术社区  ›  Andrew Garrison

UserControl公开多个内容属性!那将是多么令人兴奋啊!

  •  3
  • Andrew Garrison  · 技术社区  · 16 年前

    我正在尝试创建一个UserControl,希望它能够公开多个内容属性。然而,我失败了!

    我们的想法是创建这个伟大的用户控件(我们称之为 多内容

        <local:MultiContent>
            <local:MultiContent.ListContent>
                <ListBox x:Name="lstListOfStuff" Width="50" Height="50" />                
            </local:MultiContent.ListContent>
            <local:MultiContent.ItemContent>
                <TextBox x:Name="txtItemName" Width="50" />
            </local:MultiContent.ItemContent>
        </local:MultiContent>
    

    这将非常有用,现在我可以根据情况更改ListContent和ItemContent,在多内容用户控件中考虑通用功能。

    但是,按照我目前实现的方式,我无法访问 控制例如, txtItemName 无效的 当我尝试访问它们时:

    public MainPage() {
        InitializeComponent();
        this.txtItemName.Text = "Item 1"; // <-- txtItemName is null, so this throws an exception
    }
    

    以下是我如何实现多内容用户控件:

    XAML:MultiContent.XAML

    <UserControl x:Class="Example.MultiContent"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="400" Height="300">
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
            </Grid.ColumnDefinitions>
            <ContentControl x:Name="pnlList" Grid.Column="0" />
            <ContentControl x:Name="pnlItem" Grid.Column="1" />
        </Grid>
    </UserControl>
    

    // Namespaces Removed
    namespace Example
    {
        public partial class MultiContent : UserControl
        {
            public UIElement ListContent
            {
                get { return (UIElement)GetValue(ListContentProperty); }
                set 
                {
                    this.pnlList.Content = value;
                    SetValue(ListContentProperty, value); 
                }
            }
            public static readonly DependencyProperty ListContentProperty =
                DependencyProperty.Register("ListContent", typeof(UIElement), typeof(MultiContent), new PropertyMetadata(null));
    
            public UIElement ItemContent
            {
                get { return (UIElement)GetValue(ItemContentProperty); }
                set 
                {
                    this.pnlItem.Content = value;
                    SetValue(ItemContentProperty, value); 
                }
            }
            public static readonly DependencyProperty ItemContentProperty =
                DependencyProperty.Register("ItemContent", typeof(UIElement), typeof(MultiContent), new PropertyMetadata(null));
    
    
            public MultiContent()
            {
                InitializeComponent();
            }
        }
    }
    

    我可能完全错误地实现了这一点。有人知道我怎样才能让它正常工作吗?如何从父控件按名称访问这些UI元素?有没有关于如何做得更好的建议?谢谢

    1 回复  |  直到 16 年前
        1
  •  3
  •   Gergely Orosz    16 年前

    你肯定可以实现你的目标,但你需要采取不同的方法。

    在Silverlight中,您必须自己实现Dpendency属性。然而,您并没有按照它们应该的方式实现它们-我倾向于使用这个 dependency property generator

    DPs的一大优点是支持更改通知。因此,考虑到这一点,要使示例正常工作,您只需定义DPs:ItemContent和ListContent,它们的类型与Content(object)相同,当框架通知您其中任何一个已更改时,只需更新您的文本框即可!下面是执行此操作的代码:

    MultiContent.xaml:

       <Grid x:Name="LayoutRoot" Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
            </Grid.ColumnDefinitions>
            <ContentControl x:Name="pnlList" Grid.Column="0" />
            <ContentControl x:Name="pnlItem" Grid.Column="1" />
        </Grid>    
    

    MultiContent.xaml.cs:

    namespace MultiContent
    {
        public partial class MultiContent : UserControl
        {
            #region ListContent
    
            /// <summary>
            /// ListContent Dependency Property
            /// </summary>
            public object ListContent
            {
                get { return (object)GetValue(ListContentProperty); }
                set { SetValue(ListContentProperty, value); }
            }
            /// <summary>
            /// Identifies the ListContent Dependency Property.
            /// </summary>
            public static readonly DependencyProperty ListContentProperty =
                DependencyProperty.Register("ListContent", typeof(object),
                typeof(MultiContent), new PropertyMetadata(null, OnListContentPropertyChanged));
    
            private static void OnListContentPropertyChanged
              (object sender, DependencyPropertyChangedEventArgs e)
            {
                MultiContent m = sender as MultiContent;
                m.OnPropertyChanged("ListContent");
            }
    
            #endregion
    
            #region ItemContent
    
            /// <summary>
            /// ItemContent Dependency Property
            /// </summary>
            public object ItemContent
            {
                get { return (object)GetValue(ItemContentProperty); }
                set { SetValue(ItemContentProperty, value); }
            }
            /// <summary>
            /// Identifies the ItemContent Dependency Property.
            /// </summary>
            public static readonly DependencyProperty ItemContentProperty =
                DependencyProperty.Register("ItemContent", typeof(object),
                typeof(MultiContent), new PropertyMetadata(null, OnItemContentPropertyChanged));
    
            private static void OnItemContentPropertyChanged
              (object sender, DependencyPropertyChangedEventArgs e)
            {
                MultiContent m = sender as MultiContent;
                m.OnPropertyChanged("ItemContent");
            }
    
            #endregion
    
            /// <summary>
            ///  Event called when any chart property changes
            ///  Note that this property is not used in the example but is good to have if you plan to extend the class!
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
    
            /// <summary>
            ///  Called to invoke the property changed event
            /// </summary>
            /// <param name="propertyName">The property that has changed</param>
            protected void OnPropertyChanged(string propertyName)
            {
                if (propertyName == "ListContent")
                {
                    // The ListContent property has been changed, let's update the control!
                    this.pnlList.Content = this.ListContent;
                }
                if (propertyName == "ItemContent")
                {
                    // The ListContent property has been changed, let's update the control!
                    this.pnlItem.Content = this.ItemContent;
                }
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
            public MultiContent()
            {
                InitializeComponent();
            }
        }
    }
    

    MainPage.xaml:

        <Grid x:Name="LayoutRoot" Background="White">
            <local:MultiContent>
                <local:MultiContent.ListContent>
                    <ListBox x:Name="lstListOfStuff" Width="50" Height="50" />
                </local:MultiContent.ListContent>
                <local:MultiContent.ItemContent>
                    <TextBox x:Name="txtItemName" Width="50" />
                </local:MultiContent.ItemContent>
            </local:MultiContent>
        </Grid>
    

    这应该能奏效!

    推荐文章