与列表框中的选择对齐的问题

时间:2014-10-24 08:35:06

标签: wpf listbox custom-controls

我正在考虑创建一个矩形列表,用x,y坐标指定它们的位置,但是我看到了图形对齐的问题。我使用带有自定义布局面板的列表框。

这是主窗口的XAML:

<Window x:Class="WpfFunkyPanel.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfFunkyPanel"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <system:Double x:Key="barWidth">30</system:Double>
    <system:Double x:Key="trackHeight">24</system:Double>
    <Style x:Key="PatternGridStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="local:GridPanel.Bar" Value="{Binding Bar}"/>
        <Setter Property="local:GridPanel.Track" Value="{Binding Track}"/>
    </Style>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource PatternGridStyle}">
        <ListBox.ItemsPanel>
            <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="1" 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>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Margin="0,1,0,1">
                    <Rectangle Fill="Gray" Width="28" Height="22"></Rectangle>
                    <TextBlock Text="{Binding Text}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>
</Window>

这是网格面板:

using System;

namespace WpfFunkyPanel
{
using System.Windows;
using System.Windows.Controls;

public class GridPanel : Panel
{
    public static readonly DependencyProperty BarProperty = DependencyProperty.RegisterAttached(
        "Bar",
        typeof(int),
        typeof(GridPanel));

    public static readonly DependencyProperty TrackProperty = DependencyProperty.RegisterAttached(
        "Track",
        typeof(int),
        typeof(GridPanel));

    public static readonly DependencyProperty BarWidthProperty = DependencyProperty.Register(
        "BarWidth",
        typeof(double),
        typeof(GridPanel),
        new FrameworkPropertyMetadata(
            28.0,
            FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

    public static readonly DependencyProperty TrackHeightProperty = DependencyProperty.Register(
        "TrackHeight",
        typeof(double),
        typeof(GridPanel),
        new FrameworkPropertyMetadata(
            24.0,
            FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

    public static int GetBar(DependencyObject obj)
    {
        return (int)obj.GetValue(BarProperty);
    }

    public static void SetBar(DependencyObject obj, int value)
    {
        obj.SetValue(BarProperty, value);
    }

    public static int GetTrack(DependencyObject obj)
    {
        return (int)obj.GetValue(TrackProperty);
    }

    public static void SetTrack(DependencyObject obj, int value)
    {
        obj.SetValue(TrackProperty, value);
    }

    public GridPanel()
    {

    }

    protected override Size MeasureOverride(Size availableSize)
    {
        Size size = new Size();

        foreach (UIElement child in InternalChildren)
        {
            int bar = GetBar(child);
            int track = GetTrack(child);

            double width = (bar + 1) * BarWidth;
            double height = (track + 1) * TrackHeight;

            size.Width = Math.Max(size.Width, width);
            size.Height = Math.Max(size.Height, height);
        }

        return size;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement child in InternalChildren)
        {
            int bar = GetBar(child);
            int track = GetTrack(child);

            Rect rect = new Rect(bar * BarWidth, track * TrackHeight, BarWidth, TrackHeight);
            child.Arrange(rect);
        }

        return finalSize;
    }

    public double BarWidth
    {
        get
        {
            return (double)this.GetValue(BarWidthProperty);
        }

        set
        {
            SetValue(BarWidthProperty, value);
        }
    }

    public double TrackHeight
    {
        get
        {
            return (double)this.GetValue(TrackHeightProperty);
        }

        set
        {
            SetValue(TrackHeightProperty, value);
        }
    }
}
}

这是模式项目:

namespace WpfFunkyPanel
{
public class PatternItem
{
    private readonly int bar;

    private readonly int track;

    private readonly string text;

    public PatternItem(int bar, int track, string text)
    {
        this.bar = bar;
        this.track = track;
        this.text = text;
    }

    public int Bar
    {
        get
        {
            return bar;
        }
    }

    public int Track
    {
        get
        {
            return track;
        }
    }

    public string Text
    {
        get
        {
            return text;
        }
    }
}
}

这是集合视图模型:

namespace WpfFunkyPanel
{
using System.Collections.ObjectModel;

public class PatternContainer
{
    private int bars;

    private int tracks;

    private ObservableCollection<PatternItem> items; 

    public PatternContainer()
    {
        bars = 32;
        tracks = 24;
        items = new ObservableCollection<PatternItem>();
    }

    public void Add(PatternItem item)
    {
        items.Add(item);
    }

    public int Bars
    {
        get
        {
            return bars;
        }
    }

    public int Tracks
    {
        get
        {
            return tracks;
        }
    }

    public ObservableCollection<PatternItem> Items
    {
        get
        {
            return items;
        }
    }
}
}

最后,主窗口代码背后:

使用System.Windows;

namespace WpfFunkyPanel
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var container = new PatternContainer();

        for (int bar = 0; bar < 16; bar++)
        {
            container.Add(new PatternItem(bar, 0, "A" + (bar + 1).ToString()));
        }

        container.Add(new PatternItem(3, 2, "C4"));
        container.Add(new PatternItem(5, 5, "G6"));

        DataContext = container;
    }
}
}

这里看起来像是一个矩形:

Selection Alignment

问题是蓝色的选择框偏向左侧。另外,为了使事物对齐,我必须将视口设置为1,0,w,h而不是0,0,w,h,正如我所期望的那样。

1 个答案:

答案 0 :(得分:0)

找到一个解决方案 - 创建我自己的控件GridControl(派生自Selector)和GridItemControl(ContentControl),现在一切都有意义。

这是我的GridControlItem:

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

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

    public static readonly DependencyProperty PickedProperty = DependencyProperty.Register(
        "Picked",
        typeof(bool),
        typeof(GridControlItem),
        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 GridControlItem()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(GridControlItem), new FrameworkPropertyMetadata(typeof(GridControlItem)));
    }

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

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

我刻意使用&#34; Picked&#34;而不是&#34; IsSelected&#34;确保这有效。

现在GridControl:

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

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

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

和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 HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
                        <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:GridControlItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:GridControlItem}">
                <Border x:Name="Border">
                    <ContentPresenter />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="Picked" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="Red"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="local:GridPanel.Bar" Value="{Binding Bar}"/>
    <Setter Property="local:GridPanel.Track" Value="{Binding Track}"/>
</Style>
</ResourceDictionary>

这是MainWindow.xaml:

<Window x:Class="WpfFunkyPanel.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    xmlns:cc="clr-namespace:PatternControlLibrary;assembly=PatternControlLibrary"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>

    <DataTemplate x:Key="dataItemTemplate">
        <Grid>
            <Rectangle Fill="LightPink" Width="28" Height="22"/>
            <TextBlock Text="{Binding Text}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        </Grid>
    </DataTemplate>
</Window.Resources>

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