【问题标题】:UWP/XAML custom property which can "host" controls可以“托管”控件的 UWP/XAML 自定义属性
【发布时间】:2016-11-02 08:06:20
【问题描述】:

我实际上是在为自定义 ListView 创建一个 UserControl。 我想要达到的目标与这篇文章相同:Hide or Show stackpanel of ListViewItem with VisualStateManager。我已经实现了代码并且它可以工作,但现在我想让它更“通用”,所以我创建了一个用户控件。

我的控件分为两个网格。上层网格和折叠的隐藏网格。

我想像这样使用我的用户控件:

<controls:ExpandableListView ItemsSource="{Binding ConnectedObjects}">
    <controls:ExpandableListView.Header>
        <TextBlock Text="Hello World!" />
    </controls:ExpandableListView.Header>
    <controls:ExpandableListView.ExpandedContent>
         <Button Content="test 2" />
    </controls:ExpandableListView.ExpandedContent>
</controls:ExpandableListView>

Header 属性是要放置在上方网格中的内容,ExpandedContent 是放置在折叠网格中的内容。

在我的用户控件中,我有:

<ListView x:Name="LIST" SelectionChanged="LIST_SelectionChanged" ItemsSource="{Binding ItemsSource}">

    <!-- Item container style -->
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
    </ListView.ItemContainerStyle>

    <!-- Item template -->
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                </Grid.RowDefinitions>

                <Grid x:Name="GRID_1" Grid.Row="0">
                    <ContentPresenter Content="{Binding Path=Header}" />
                </Grid>

                <Grid x:Name="GRID_2" Grid.Row="1" Visibility="Collapsed">
                    <ContentPresenter Content="{Binding Path=ExpandedContent}" />
                </Grid>

                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal"></VisualState>
                        <VisualState x:Name="Selected">
                            <VisualState.Setters>
                                <Setter Target="GRID_2.Visibility" Value="Visible"></Setter>
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>

            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

用户控件后面有代码

public sealed partial class ExpandableListView : UserControl
{
    private static readonly DependencyProperty ItemsSourceProperty = 
        DependencyProperty.Register(
            "ItemsSource", 
            typeof(IEnumerable), 
            typeof(ExpandableListView),
            new PropertyMetadata(null));

    public static readonly DependencyProperty HeaderContentProperty =
        DependencyProperty.Register(
            "Header",
            typeof(Object),
            typeof(ExpandableListView),
            new PropertyMetadata(null));

    public static readonly DependencyProperty ExpandedContentProperty =
        DependencyProperty.Register(
            "ExpandedContent",
            typeof(Object),
            typeof(ExpandableListView),
            new PropertyMetadata(null));

    public IEnumerable ItemsSource
    {
        get { return this.GetValue(ItemsSourceProperty) as IEnumerable; }
        set { this.SetValue(ItemsSourceProperty, value); }
    }

    public Object Header
    {
        get { return (Object)this.GetValue(HeaderContentProperty); }
        set { this.SetValue(HeaderContentProperty, value); }
    }

    public Object ExpandedContent
    {
        get { return (Object)this.GetValue(ExpandedContentProperty); }
        set { this.SetValue(ExpandedContentProperty, value); }
    }

    public ExpandableListView()
    {
        this.InitializeComponent();
        this.LIST.DataContext = this;
    }

    private void LIST_SelectionChanged(Object sender, SelectionChangedEventArgs e)
    {
    }

    private void SetInEditMode()
    {
        VisualStateManager.GoToState(this, "Selected", true);
    }

    private void SetInViewMode()
    {
        VisualStateManager.GoToState(this, "Normal", true);
    }
}

【问题讨论】:

  • 你有什么问题?
  • 我的问题是如何在我的 ListView 中显示我的 &lt;controls:ExpandableListView.ExpandedContent&gt;&lt;controls:ExpandableListView.Header&gt; 之间定义的内容。我正在使用 ItemTemplate 来格式化 Item 单元格,我有 HeaderExpandedContent,它们是 FrameworkElements。但它似乎不像那样工作。我也尝试过使用 ContentControl,但没有成功。

标签: c# .net xaml user-controls uwp


【解决方案1】:
   <Grid x:Name="GRID_2" Grid.Row="1" Visibility="Collapsed">
      <ContentPresenter Content="{Binding MyUsersContent }"/>
   </Grid>

在您的控制 CS 文件中

public class YourControl{  

     public Object MyUsersContent
     {
         get { return (Object)GetValue(MyUsersContentProperty); }
         set { SetValue(MyUsersContentProperty, value); }
     }
    
     public static readonly DependencyProperty MyUsersContentProperty =
                   DependencyProperty.Register("MyUsersContent", 
                       typeof(Object), typeof(YoutControl), new PropertyMetadata());   
 }

这可能是最简单的方法。这就是我们需要查看您的代码的原因。因为实现此功能的方式会有所不同。如果您在绑定时遇到问题,那么您可以在 OnApplyTemplate 函数中获取您的控制权并手动将其注入。

在继续之前,我强烈建议您阅读本教程。它将让您了解如何解决这个问题以及您将面临的许多其他问题。

How to create a Custom Control in WPF

【讨论】:

  • 感谢您的回答,我已经编辑了我的原始帖子,添加了用户控件背后的代码。还尝试添加&lt;ContentPresenter Content="{Binding RelativeSource= {RelativeSource TemplatedParent}, Path=MyUsersContent }"/&gt;,但不幸的是它不起作用。
  • 这就是为什么我说其余的代码很重要。而不是使用模板化的父级直接绑定到它。
【解决方案2】:

我相信您需要添加内容属性来指定将哪个属性用作内容。示例:

[ContentProperty("ExpandedContent")]
public sealed partial class ExpandableListView : UserControl
{
...
    public static readonly DependencyProperty ExpandedContentProperty =
        DependencyProperty.Register(
            "ExpandedContent",
            typeof(Object),
            typeof(ExpandableListView),
            new PropertyMetadata(null));
...
    public Object ExpandedContent
    {
        get { return (Object)this.GetValue(ExpandedContentProperty); }
        set { this.SetValue(ExpandedContentProperty, value); }
    }

...
}

另外我更喜欢在依赖属性声明中使用nemeof()。它使代码重构和重命名更安全:

public static readonly DependencyProperty ExpandedContentProperty =
    DependencyProperty.Register(
        nameof(ExpandedContent),
        typeof(Object),
        typeof(ExpandableListView),
        new PropertyMetadata(null));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 2013-12-13
    • 2017-11-17
    • 2014-11-26
    相关资源
    最近更新 更多