在WPF中,ListBoxItem与ListBox的关联是什么?

时间:2014-10-28 14:38:38

标签: wpf listbox custom-controls listboxitem

这与Issues with alignment with selection in a listbox

有关

我有一个用两个自定义控件替换ListBox - GridControl和GridItemControl。我看到的问题是两者之间没有任何联系,即当你向GridControl添加项目时,它们不是GridItemControl。我可以说,因为mousedown事件没有发生。

如果我使用XAML在GridControl中嵌入GridItemControl但是它与ItemSource不同,我确实看到了一个关联。

这是GridControl:

public class GridControl : Selector
{
    static GridControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(GridControl), new FrameworkPropertyMetadata(typeof(GridControl)));
    }
}

这是GridItemControl:

public class GridItemControl : ContentControl
{
    public static readonly DependencyProperty BarProperty = DependencyProperty.Register(
        "Bar",
        typeof(int),
        typeof(GridItemControl),
        new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static readonly DependencyProperty TrackProperty = DependencyProperty.Register(
        "Track",
        typeof(int),
        typeof(GridItemControl),
        new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static readonly DependencyProperty PickedProperty = DependencyProperty.Register(
        "Picked",
        typeof(bool),
        typeof(GridItemControl),
        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public int Bar
    {
        get
        {
            return (int)this.GetValue(BarProperty);
        }

        set
        {
            SetValue(BarProperty, value);
        }
    }

    public int Track
    {
        get
        {
            return (int)this.GetValue(TrackProperty);
        }

        set
        {
            SetValue(TrackProperty, value);
        }
    }

    public bool Picked
    {
        get
        {
            return (bool)this.GetValue(PickedProperty);
        }

        set
        {
            SetValue(PickedProperty, value);
        }
    }

    static GridItemControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(GridItemControl), new FrameworkPropertyMetadata(typeof(GridItemControl)));
    }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);

        if (e.ChangedButton == MouseButton.Left)
        {
            this.Picked = true;
            e.Handled = true;
        }
    }
}

这是Generic.xaml:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PatternControlLibrary"
xmlns:system="clr-namespace:System;assembly=mscorlib">

<system:Double x:Key="barWidth">30</system:Double>
<system:Double x:Key="trackHeight">24</system:Double>

<Style TargetType="{x:Type local:GridControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:GridControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer>
                        <ItemsPresenter />
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <local:GridPanel VerticalAlignment="Top" BarWidth="{StaticResource barWidth}" TrackHeight="{StaticResource trackHeight}">
                    <local:GridPanel.Background>
                        <DrawingBrush TileMode="Tile" ViewboxUnits="Absolute" ViewportUnits="Absolute">
                            <DrawingBrush.Viewbox>
                                <Rect X="0" Y="0" Width="{StaticResource barWidth}" Height="{StaticResource trackHeight}"/>
                            </DrawingBrush.Viewbox>
                            <DrawingBrush.Viewport>
                                <Rect X="0" Y="0" Width="{StaticResource barWidth}" Height="{StaticResource trackHeight}"/>
                            </DrawingBrush.Viewport>
                            <DrawingBrush.Drawing>
                                <GeometryDrawing Brush="LightGray">
                                    <GeometryDrawing.Pen>
                                        <Pen Brush="Black" Thickness="1"/>
                                    </GeometryDrawing.Pen>
                                    <GeometryDrawing.Geometry>
                                        <PathGeometry>
                                            <PathFigure IsFilled="True">
                                                <LineSegment>
                                                    <LineSegment.Point>
                                                        <Point X="{StaticResource barWidth}" Y="0"/>
                                                    </LineSegment.Point>
                                                </LineSegment>
                                                <LineSegment>
                                                    <LineSegment.Point>
                                                        <Point X="{StaticResource barWidth}" Y="{StaticResource trackHeight}"/>
                                                    </LineSegment.Point>
                                                </LineSegment>
                                                <LineSegment>
                                                    <LineSegment.Point>
                                                        <Point X="0" Y="{StaticResource trackHeight}"/>
                                                    </LineSegment.Point>
                                                </LineSegment>
                                                <LineSegment/>
                                            </PathFigure>
                                        </PathGeometry>
                                    </GeometryDrawing.Geometry>
                                </GeometryDrawing>
                            </DrawingBrush.Drawing>
                        </DrawingBrush>
                    </local:GridPanel.Background>
                </local:GridPanel>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type local:GridItemControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:GridItemControl}">
                <Border>
                    <ContentPresenter />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="local:GridPanel.Bar" Value="{Binding Bar}"/>
    <Setter Property="local:GridPanel.Track" Value="{Binding Track}"/>
</Style>
</ResourceDictionary>

如果我在MainWindow.xaml中使用以下内容,我会得到我期望的内容:

<Grid>
    <cc:GridControl 
        ItemTemplate="{StaticResource dataItemTemplate}">
        <cc:GridItemControl Content="Test" Bar="5" Track="3"/>
    </cc:GridControl>
</Grid>

(根据Bar and Track,盒子没有对齐,但这是另一个问题!)。

如果我将其替换为我期望使用的内容:

<Grid>
    <cc:GridControl 
        ItemsSource="{Binding Items}"
        ItemTemplate="{StaticResource dataItemTemplate}"/>
</Grid>

然后没有使用GridItemControl,因为当我点击一个单元格时,我没有看到mousedown事件。

1 个答案:

答案 0 :(得分:3)

如果您实现自定义ItemsControl并想要使用自定义容器类型,则需要覆盖一些方法:

protected override DependencyObject GetContainerForItemOverride()
{
    return new GridItemControl();
}

protected override bool IsItemItsOwnContainerOverride(object item)
{
    return (item is GridItemControl);
}

上述方法是ItemsControl如何为基础数据项生成容器元素。例如,ListBox会覆盖这些内容以提供ListBoxItem个容器,而不是标准ContentControl

另外,如果您想坚持使用已接受的命名约定,GridItemControl应该被称为GridControlItem