UWP / XAML自定义属性,可以“托管”控件

时间:2016-06-30 09:48:11

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

我实际上是为自定义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);
    }
}

2 个答案:

答案 0 :(得分:1)

我认为您需要添加内容属性以指定将哪个属性用作内容。例如:

[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));

答案 1 :(得分:0)

   <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