具有多个交互式UI元素的数据组列表

时间:2012-02-15 22:06:03

标签: wpf

我正在开发一个WPF应用程序,这是我的第一个,所以我正在学习。 基本情况很好,但我遇到了我现在正在尝试做的问题。似乎有很多方法可行,但我很确定我会走上使它变得更难的道路。

我需要的是关于实现一个UI的最简单方法的一些指导。

我正在使用c#4,wpf和MVVM模式。

我想要显示的数据如下所示:

obj1 ----< obj2 ----< OBJ 3 即单个obj1有许多obj2,它有许多(特别是1-3)obj3的

在我的屏幕上,我希望看到obj2元素的list / datagrid类型视图,其中嵌套了相关的obj3元素。

obj2元素需要显示一些文本值和一个复选框(在切换时将触发视图模型中的相应命令)。 obj3元素需要显示一个图像,可能是一些文本并且是可点击的(再次,向视图模型发出适当的命令)。

首先,我研究了为obj3元素创建自定义控件,基于ItemsControl的自定义控件,用于obj3元素列表,另一个自定义控件用于obj2元素,最后是另一个自定义控件,用于显示obj2元素列表。

然而,从某种程度上说,我感觉我已经大大过度复杂了。 我可以只使用用户控件吗?我甚至根本不需要它们,或者我可以只使用带有模板的常规List控件吗?

一些指示会非常受欢迎。 感谢。

1 个答案:

答案 0 :(得分:0)

我花了很长时间才开始工作,因为我想要分享......

答案结果是一个嵌套列表控件,其中包含每个列表中项目的数据模板和相关视图模型。列表控件在WPF中比Winforms更灵活,你可以用它做任何事情。

我发现许多不同的东西在许多不同的网站上有所帮助,但核心细节来自Dr.WPF:http://drwpf.com/blog/category/collections/

我不会发布所有代码,因为它相当长。它的核心是首先在用户控件中设置列表视图:

<ListView Name="list" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
    HorizontalContentAlignment="Stretch" Focusable="False"
    IsSynchronizedWithCurrentItem="True" ItemsPanel="{StaticResource VerticalItemsPanel}" 
    ItemContainerStyle="{StaticResource Obj2ContainerStyle}" ItemsSource="{Binding Obj2List}">
</ListView>

这里的键是ItemsPanel和ItemContainerStyle。它们定义了包含所有列表项的面板的属性以及每个列表项的样式。 它们包含在用户控件的资源中。

<ItemsPanelTemplate x:Key="VerticalItemsPanel">
    <StackPanel Orientation="Vertical" Focusable="False" HorizontalAlignment="Stretch" />
</ItemsPanelTemplate>
<Style x:Key="Obj2ContainerStyle" TargetType="{x:Type ListViewItem}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=Enabled}" Value="False">
            <Setter Property="Background" Value="LightSalmon"></Setter>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=Enabled}" Value="True">
            <Setter Property="Background" Value="PaleGreen"></Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

我也有数据模板。第一个告诉系统使用第二个来显示Obj2ViewModel类型的对象

<DataTemplate DataType="{x:Type src:Obj2ViewModel}">
    <ContentControl x:Name="Obj2Host" Focusable="False" Content="{Binding}"
                        ContentTemplate="{StaticResource Obj2ViewTemplate}" />
</DataTemplate>

<DataTemplate x:Key="Obj2ViewTemplate">
    <DataTemplate.Resources>
        <ItemsPanelTemplate x:Key="HorizontalItemsPanel">
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
        <Style x:Key="Obj3ContainerStyle" TargetType="{x:Type ListViewItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Grid>
                            <Rectangle StrokeThickness="1" Stroke="#FF000000" Margin="0" />
                            <ContentPresenter x:Name="ContentHost" Margin="{TemplateBinding Padding}" 
                                                              HorizontalAlignment="Center" VerticalAlignment="Center" />
                        </Grid>
                     </ControlTemplate>
                 </Setter.Value>
             </Setter>
         </Style>
    <Style x:Key="LabelStyle" TargetType="{x:Type Label}">
        <Setter Property="Padding" Value="0,0,4,0" />
        <Setter Property="HorizontalAlignment" Value="Left" />
    </Style>
    <Style x:Key="DataStyle" TargetType="{x:Type TextBlock}">
        <Setter Property="Padding" Value="0,0,4,0" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="FontWeight" Value="Bold" />
    </Style>
     </DataTemplate.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0" Content="{StaticResource Label1Text}" Style="{StaticResource LabelStyle}"/>
        <Label Grid.Row="1" Grid.Column="0" Content="{StaticResource Label2Text}" Style="{StaticResource LabelStyle}"/>
        <Label Grid.Row="2" Grid.Column="0" Content="{StaticResource Label3Text}" Style="{StaticResource LabelStyle}"/>
        <Label Grid.Row="3" Grid.Column="0" Content="{StaticResource Label4Text}" Style="{StaticResource LabelStyle}"/>
        <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Property1}" Style="{StaticResource DataStyle}"/>
        <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Property2}" Style="{StaticResource DataStyle}"/>
        <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Property3}" Style="{StaticResource DataStyle}"/>
        <TextBlock Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Property4}" Style="{StaticResource DataStyle}"/>
        <ListView Grid.Row="0" Grid.RowSpan="3" Grid.Column="2" Name="Obj3List" 
                    HorizontalAlignment="Right" VerticalAlignment="Center"
                    IsSynchronizedWithCurrentItem="True"
                    ItemsPanel="{StaticResource HorizontalItemsPanel}"
                    ItemsSource="{Binding Obj3s}" 
                    ItemContainerStyle="{StaticResource Obj3ContainerStyle}"
                    BorderThickness="0"
                    Background="Transparent">
        </ListView>
        <CheckBox Grid.Row="0" Grid.RowSpan="4" Grid.Column="3" VerticalAlignment="Center" 
                    IsChecked="{Binding Property5}" IsEnabled="{Binding NotExpired}" >
        </CheckBox>
        <Image Grid.Row="0" Grid.RowSpan="4" Grid.Column="4" Source="{StaticResource DeleteIcon}" Stretch="None">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseUp">
                    <cmd:EventToCommand PassEventArgsToCommand="False" Command="{Binding DeleteObj2Command, Mode=OneWay}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Image>
    </Grid>
</DataTemplate>

上面的第二个数据模板包含另一个列表视图。这一个包含Obj3项目。 这些样式在DataTemplate的资源部分中指定。 最后,User控件的资源还包含Obj3元素的数据模板:

<DataTemplate DataType="{x:Type src:Obj3ViewModel}">
    <ContentControl x:Name="Obj3Host" Focusable="False" Content="{Binding}" 
        ContentTemplate="{StaticResource Obj3ViewTemplate}" />
</DataTemplate>
<DataTemplate x:Key="Obj3ViewTemplate">
    <Image Source="{Binding Image}" Stretch="None">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseUp">
                <cmd:EventToCommand PassEventArgsToCommand="False" Command="{Binding ToggleEnabledCommand, Mode=OneWay}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Image>
</DataTemplate>

请注意,EventToCommand的功能归功于MVVM Light工具包。它不是标准的.NET。