我正在尝试创建一个UserControl,希望它能够公开多个内容属性。但是,我充满失败!

这个想法是创建一个很好的用户控件(我们将其称为MultiContent),该控件公开两个内容属性,以便我可以执行以下操作:

    <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,并将常见功能分解为MultiContent用户控件。

但是,以我当前实现此方式的方式,我无法访问MultiContent控件的这些内容属性内的UI元素。例如,当我尝试访问它们时,lstListOfStuff和txtItemName都为null:

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


这是我实现MultiContent用户控件的方式:

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>


背后的代码:MultiContent.xaml.cs

// 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元素?关于如何做得更好的任何建议?谢谢!

最佳答案

您绝对可以实现自己的目标,但您需要采用其他方法。

在您的解决方案中,您尝试拥有UIElement的依赖项属性-且因为它从未设置且默认值为null,因此您将获得NullReference异常。您可以通过将默认值从null更改为新的TextBox或类似的方法继续进行,但是即使它确实起作用了,它仍然感觉像是被黑客入侵了。

在Silverlight中,您必须自己实现Dpendency属性。但是,您尚未实现它们,应该实现它们-我倾向于使用此dependency property generator来实现。

DP的一大优点是它们支持变更通知。因此,请记住,要使示例工作正常,所有要做的就是将DP定义为:与Content(对象)类型相同的ItemContent和ListContent,并且当框架通知您其中一个已更改时,只需更新您的文本框即可。 !因此,这是执行此操作的代码:

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>


这应该可以解决问题!

关于silverlight - UserControl公开多个内容属性!那将是多么令人兴奋!,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2068125/

10-11 14:26