0

我有以下 CustomControl 想用作横幅的基础:

XAML:

<UserControl x:Name="userControl"
    x:Class="Nova.WinRT.Controls.BannerPanel"
    ...>

    <Grid Background="#BF8B8B8B">
        <Grid Height="400" Background="#FF050A7C" VerticalAlignment="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="50"/>
            </Grid.RowDefinitions>
            <TextBlock x:Name="_Title" Text="Title" FontSize="30" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            <ContentPresenter x:Name="_Content" Grid.Row="1"/>
            <StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Center">
                <Button x:Name="_OK" Content="OK" HorizontalAlignment="Center" Click="OkPressed" FontSize="18" Width="100" Margin="20,0" />
                <Button x:Name="_Cancel" Content="Cancel" HorizontalAlignment="Center" Click="CancelPressed" FontSize="18" Width="100" Margin="20,0" />
            </StackPanel>
        </Grid>
    </Grid>
</UserControl>

C#:

public sealed partial class BannerPanel : UserControl
{
    /// <summary>
    /// Title of the Banner
    /// </summary>
    public string Title
    {
        get { return _Title.Text; }
        set { _Title.Text = value; }
    }

    /// <summary>
    /// The visibility of the OK button
    /// </summary>
    public Visibility OKVisibility
    {
        get { return _OK.Visibility; }
        set { _OK.Visibility = value; }
    }

    /// <summary>
    /// The visibility of the Cancel button
    /// </summary>
    public Visibility CancelVisibility 
    {
        get { return _Cancel.Visibility; }
        set { _Cancel.Visibility = value; }
    }

    /// <summary>
    /// The inner content of the panel
    /// </summary>
    public FrameworkElement InnerContent 
    {
        get { return (FrameworkElement)_Content.Content; }
        set { _Content.Content = value; }
    }

    /// <summary>
    /// Fires when the Ok button is clicked
    /// </summary>
    public event RoutedEventHandler OkClick;

    /// <summary>
    /// Fires when the Cancel button is clicked
    /// </summary>
    public event RoutedEventHandler CancelClick;
};

但是当我使用它时(参见下面的 XAML),自动生成的代码在内部内容中找不到元素:

XAML:

<Controls:BannerPanel x:Name="Banner" Title="Terms and Policy" CancelVisibility="Collapsed" OkClick="OnTermsAccepted">
    <Controls:BannerPanel.InnerContent>
        <ScrollViewer Width="500">
            <TextBlock x:Name="TermsText" TextWrapping="Wrap" FontSize="12" />
        </ScrollViewer>
    </Controls:BannerPanel.InnerContent>
</Controls:BannerPanel>

C#:

public sealed partial class TermsBanner : UserControl
{
    /// <summary>
    /// Constructor
    /// </summary>
    public TermsBanner()
    {
        this.InitializeComponent();

        // Why do I have to find TermsText Manually like this??????
        TermsText = (Banner.InnerContent as ScrollViewer).Content as TextBlock;
        TermsText.Text = TermsOfUse;
    }
};

为什么我必须手动将变量 TermsText 指向正确的东西?为什么它不能像通常那样使用 FindName() 自动找到它?

4

1 回答 1

4
  1. 您应该定义DependencyProperty属性而不是常规属性。
  2. 派生自ContentControl而不是UserControl.
  3. 将您的 XAML 放在 Themes/Generic.xaml 中的Style/Setter/Property="Template" Value=".... 如果您使用 Templated Control VS item 模板创建控件,它会自动发生。
  4. 使用 TemplateBinding 将内部模板元素的属性绑定到您的控件属性。

FindName 可能无法跨名称范围工作。我从不使用它。

原谅错别字。在手机上打字。

这是一个解决方案:

创建模板化控件(也称为自定义控件 - 不要与 UserControl 混淆)并将其修改为派生自ContentControl而不是Control

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

// The Templated Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234235

namespace App124
{
    [TemplatePart(Name = "_OK", Type = typeof(Button))]
    [TemplatePart(Name = "_Cancel", Type = typeof(Button))]
    public sealed class BannerPanel : ContentControl
    {
        #region Title
        /// <summary>
        /// Title Dependency Property
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register(
                "Title",
                typeof(string),
                typeof(BannerPanel),
                new PropertyMetadata(null, OnTitleChanged));

        /// <summary>
        /// Gets or sets the Title property. This dependency property 
        /// indicates ....
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        /// Handles changes to the Title property.
        /// </summary>
        /// <param name="d">
        /// The <see cref="DependencyObject"/> on which
        /// the property has changed value.
        /// </param>
        /// <param name="e">
        /// Event data that is issued by any event that
        /// tracks changes to the effective value of this property.
        /// </param>
        private static void OnTitleChanged(
            DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (BannerPanel)d;
            string oldTitle = (string)e.OldValue;
            string newTitle = target.Title;
            target.OnTitleChanged(oldTitle, newTitle);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes
        /// to the Title property.
        /// </summary>
        /// <param name="oldTitle">The old Title value</param>
        /// <param name="newTitle">The new Title value</param>
        private void OnTitleChanged(
            string oldTitle, string newTitle)
        {
        }
        #endregion

        #region OKVisibility
        /// <summary>
        /// OKVisibility Dependency Property
        /// </summary>
        public static readonly DependencyProperty OKVisibilityProperty =
            DependencyProperty.Register(
                "OKVisibility",
                typeof(Visibility),
                typeof(BannerPanel),
                new PropertyMetadata(Visibility.Visible, OnOKVisibilityChanged));

        /// <summary>
        /// Gets or sets the OKVisibility property. This dependency property 
        /// indicates ....
        /// </summary>
        public Visibility OKVisibility
        {
            get { return (Visibility)GetValue(OKVisibilityProperty); }
            set { SetValue(OKVisibilityProperty, value); }
        }

        /// <summary>
        /// Handles changes to the OKVisibility property.
        /// </summary>
        /// <param name="d">
        /// The <see cref="DependencyObject"/> on which
        /// the property has changed value.
        /// </param>
        /// <param name="e">
        /// Event data that is issued by any event that
        /// tracks changes to the effective value of this property.
        /// </param>
        private static void OnOKVisibilityChanged(
            DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (BannerPanel)d;
            Visibility oldOKVisibility = (Visibility)e.OldValue;
            Visibility newOKVisibility = target.OKVisibility;
            target.OnOKVisibilityChanged(oldOKVisibility, newOKVisibility);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes
        /// to the OKVisibility property.
        /// </summary>
        /// <param name="oldOKVisibility">The old OKVisibility value</param>
        /// <param name="newOKVisibility">The new OKVisibility value</param>
        private void OnOKVisibilityChanged(
            Visibility oldOKVisibility, Visibility newOKVisibility)
        {
        }
        #endregion

        #region CancelVisibility
        /// <summary>
        /// CancelVisibility Dependency Property
        /// </summary>
        public static readonly DependencyProperty CancelVisibilityProperty =
            DependencyProperty.Register(
                "CancelVisibility",
                typeof(Visibility),
                typeof(BannerPanel),
                new PropertyMetadata(Visibility.Visible, OnCancelVisibilityChanged));

        /// <summary>
        /// Gets or sets the CancelVisibility property. This dependency property 
        /// indicates ....
        /// </summary>
        public Visibility CancelVisibility
        {
            get { return (Visibility)GetValue(CancelVisibilityProperty); }
            set { SetValue(CancelVisibilityProperty, value); }
        }

        /// <summary>
        /// Handles changes to the CancelVisibility property.
        /// </summary>
        /// <param name="d">
        /// The <see cref="DependencyObject"/> on which
        /// the property has changed value.
        /// </param>
        /// <param name="e">
        /// Event data that is issued by any event that
        /// tracks changes to the effective value of this property.
        /// </param>
        private static void OnCancelVisibilityChanged(
            DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (BannerPanel)d;
            Visibility oldCancelVisibility = (Visibility)e.OldValue;
            Visibility newCancelVisibility = target.CancelVisibility;
            target.OnCancelVisibilityChanged(oldCancelVisibility, newCancelVisibility);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes
        /// to the CancelVisibility property.
        /// </summary>
        /// <param name="oldCancelVisibility">The old CancelVisibility value</param>
        /// <param name="newCancelVisibility">The new CancelVisibility value</param>
        private void OnCancelVisibilityChanged(
            Visibility oldCancelVisibility, Visibility newCancelVisibility)
        {
        }
        #endregion

        /// <summary>
        /// Fires when the Ok button is clicked
        /// </summary>
        public event RoutedEventHandler OkClick;

        /// <summary>
        /// Fires when the Cancel button is clicked
        /// </summary>
        public event RoutedEventHandler CancelClick;

        public BannerPanel()
        {
            this.DefaultStyleKey = typeof(BannerPanel);
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var cancelButton = (Button)GetTemplateChild("_Cancel");
            var okButton = (Button)GetTemplateChild("_OK");
            cancelButton.Click += CancelClick;
            okButton.Click += OkClick;
        }
    }
}

将Themes/Generic.xaml更新为:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App124">

    <Style
        TargetType="local:BannerPanel">
        <Setter
            Property="HorizontalContentAlignment"
            Value="Left" />
        <Setter
            Property="VerticalContentAlignment"
            Value="Top" />
        <Setter
            Property="Title"
            Value="Title" />
        <Setter
            Property="OKVisibility"
            Value="Visible" />
        <Setter
            Property="CancelVisibility"
            Value="Visible" />
        <Setter
            Property="Template">
            <Setter.Value>
                <ControlTemplate
                    TargetType="local:BannerPanel">
                    <Grid
                        Background="#BF8B8B8B">
                        <Grid
                            Height="400"
                            Background="#FF050A7C"
                            VerticalAlignment="Center">
                            <Grid.RowDefinitions>
                                <RowDefinition
                                    Height="50" />
                                <RowDefinition
                                    Height="*" />
                                <RowDefinition
                                    Height="50" />
                            </Grid.RowDefinitions>
                            <TextBlock
                                x:Name="_Title"
                                Text="{TemplateBinding Title}"
                                FontSize="30"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center" />
                            <ContentPresenter
                                Grid.Row="1"
                                ContentTemplate="{TemplateBinding ContentTemplate}"
                                ContentTransitions="{TemplateBinding ContentTransitions}"
                                Content="{TemplateBinding Content}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                Margin="{TemplateBinding Padding}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                            <StackPanel
                                Orientation="Horizontal"
                                Grid.Row="2"
                                HorizontalAlignment="Center">
                                <Button
                                    x:Name="_OK"
                                    Content="OK"
                                    Visibility="{TemplateBinding OKVisibility}"
                                    HorizontalAlignment="Center"
                                    FontSize="18"
                                    Width="100"
                                    Margin="20,0" />
                                <Button
                                    x:Name="_Cancel"
                                    Content="Cancel"
                                    Visibility="{TemplateBinding CancelVisibility}"
                                    HorizontalAlignment="Center"
                                    FontSize="18"
                                    Width="100"
                                    Margin="20,0" />
                            </StackPanel>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

这是它在MainPage.xaml中的使用方式:

<Page
    x:Class="App124.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App124"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid
        Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <local:BannerPanel
            x:Name="Banner"
            Title="Terms and Policy"
            CancelVisibility="Collapsed"
            OkClick="OnTermsAccepted">
            <ScrollViewer
                Width="500">
                <TextBlock
                    x:Name="TermsText"
                    Text="Terms and Conditions"
                    TextWrapping="Wrap"
                    FontSize="12" />
            </ScrollViewer>
        </local:BannerPanel>
    </Grid>
</Page>

MainPage.xaml.cs 后面的代码

using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace App124
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private void OnTermsAccepted(object sender, RoutedEventArgs e)
        {
            new MessageDialog(TermsText.Text).ShowAsync();
        }
    }
}
于 2013-03-02T21:38:21.543 回答