【问题标题】:Selecting bound ListBox items with Canvas as ItemsPanelTemplate使用 Canvas 作为 ItemsPanelTemplate 选择绑定的 ListBox 项目
【发布时间】:2013-10-29 04:44:23
【问题描述】:

我正在编写一个日程安排工具,我希望有一个类似于“Day”的视图,它在许多日历应用程序中都可用。

它是作为一个 ListBox 完成的,因此用户可以选择一些事件。当我尝试绑定事件时会出现问题 - 选择无法按预期工作。我的意思是它看起来像是被拉伸到容器的最顶部,而且点击事件不是在元素上处理,而是在元素和容器顶部边缘之间的空间上处理。

这是一个示例:在左侧 - 它应该如何工作和外观,这是通过手动放置两个 ListBoxItem 来完成的。在右侧,使用绑定。

我将这两种情况的可视化树与 WPF 调试工具进行了比较,并且在例如ContentPresenter 的东西,但我不明白那里发生了什么,为什么会出现差异以及如何删除它。

这是我的 XAML:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="PLA1.MainWindow"
    x:Name="Window"
    xmlns:local="clr-namespace:PLA1"
    Title="MainWindow"
    Width="640" Height="480">

    <Window.Resources>
        <local:MarginConverter x:Key="marginConverter"/>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <ListBox Margin="8,8,0,8" Background="#C9BBC0FF" HorizontalAlignment="Left" Width="160">
           <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <ListBoxItem Margin="{Binding Path=StartMinutes, Converter={StaticResource marginConverter}}" Height="{Binding Path=Duration}" Width="150" Background="#8000FF00" Foreground="White" BorderThickness="2" BorderBrush="#80000000">
                        <StackPanel>
                            <TextBlock Text="{Binding Path=Name}" Margin="5,0,0,0" Width="130" TextWrapping="Wrap" FontWeight="Bold" FontSize="18" />
                            <TextBlock Text="{Binding Path=Place}"  Margin="8,0,0,0" FontSize="14"/>
                        </StackPanel>
                    </ListBoxItem>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.Effect>
                <DropShadowEffect Opacity="0.625"/>
            </ListBox.Effect>

            <!-- uncomment these two lines to test binding -->
            <!--local:Event Duration="200" StartMinutes="60" Name="Sprawdzian" Place="EA32" />
            <local:Event Duration="120" StartMinutes="300" Name="Oddanie projektu" Place="308" /-->

            <ListBoxItem Margin="0,60,0,0" Height="200" Width="150" Background="#8000FF00" Foreground="White" BorderThickness="2" BorderBrush="#80000000">
                <StackPanel>
                    <TextBlock Text="Sprawdzian" Margin="5,0,0,0" Width="130" TextWrapping="Wrap" FontWeight="Bold" FontSize="18" />
                    <TextBlock Text="EA32"  Margin="8,0,0,0" FontSize="14"/>
                </StackPanel>
            </ListBoxItem>      

            <ListBoxItem Margin="0,300,0,0" Height="120" Width="150" Background="#8000FF00" Foreground="White" BorderThickness="2" BorderBrush="#80000000">
                <StackPanel>
                    <TextBlock Text="Oddanie projektu" Margin="5,0,0,0" Width="130" TextWrapping="Wrap" FontWeight="Bold" FontSize="18" />
                    <TextBlock Text="308"  Margin="8,0,0,0" FontSize="14"/>
                </StackPanel>
            </ListBoxItem>  
        </ListBox>
    </Grid>
</Window>

事件类:

public class Event
{
    public int StartMinutes { get;set; }
    public int Duration { get; set; }
    public string Name { get; set; }
    public string Place { get; set; }

    public Event() { }
}

MarginConverter 类:

public class MarginConverter : IValueConverter
{
    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new Thickness(0, (int)(value), 0, 0);
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

【问题讨论】:

    标签: wpf binding datatemplate


    【解决方案1】:

    尝试如下更新您的 ListBox:

      <ListBox Margin="8,8,0,8" Background="#C9BBC0FF" HorizontalAlignment="Left" Width="160">
           <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
               <Style TargetType="ListBoxItem">
                        <Setter Property="Height" Value="{Binding Duration}"/>
                         <Setter Property="Margin" Value="{Binding Path=StartMinutes, Converter={StaticResource marginConverter}}" />
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                        <StackPanel Background="#8000FF00" BorderThickness="2" BorderBrush="#80000000">
                            <TextBlock Text="{Binding Path=Name}" Margin="5,0,0,0" Width="130" TextWrapping="Wrap" FontWeight="Bold" FontSize="18" />
                            <TextBlock Text="{Binding Path=Place}"  Margin="8,0,0,0" FontSize="14"/>
                        </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
    

    【讨论】:

      【解决方案2】:

      您应该在ListBox 资源中为ListBoxItem 添加样式,并在其中设置适当的属性并更改ItemTemplate

      <ListBox Margin="8,8,0,8" Background="#C9BBC0FF" HorizontalAlignment="Left" Width="160">
          <ListBox.Resources>                   
              <Style TargetType="ListBoxItem">
                  <Setter Property="Margin" Value="{Binding Path=StartMinutes, Converter={StaticResource marginConverter}}" />
                  <Setter Property="Height" Value="{Binding Path=Duration}" />
                  <Setter Property="Foreground" Value="White" />
                  <Setter Property="BorderThickness" Value="2" />
                  <Setter Property="BorderBrush" Value="#80000000" />
                  <Setter Property="Width" Value="150" />
                  <Setter Property="Background" Value="#8000FF00" />
              </Style>
          </ListBox.Resources>
          <ItemsControl.ItemsPanel>
              <ItemsPanelTemplate>
                  <Canvas />
              </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>
          <ListBox.ItemTemplate>
              <DataTemplate>                    
                      <StackPanel>
                          <TextBlock Text="{Binding Path=Name}" Margin="5,0,0,0" Width="130" TextWrapping="Wrap" FontWeight="Bold" FontSize="18" />
                          <TextBlock Text="{Binding Path=Place}"  Margin="8,0,0,0" FontSize="14"/>
                      </StackPanel>                        
              </DataTemplate>
          </ListBox.ItemTemplate>
          <ListBox.Effect>
              <DropShadowEffect Opacity="0.625"/>
          </ListBox.Effect>
      
          <!-- uncomment these two lines to test binding -->
          <local:Event Duration="200" StartMinutes="60" Name="Sprawdzian" Place="EA32" />
          <local:Event Duration="120" StartMinutes="300" Name="Oddanie projektu" Place="308" />
      
          <!--<ListBoxItem Margin="0,60,0,0" Height="200" Width="150" Background="#8000FF00" Foreground="White" BorderThickness="2" BorderBrush="#80000000">
              <StackPanel>
                  <TextBlock Text="Sprawdzian" Margin="5,0,0,0" Width="130" TextWrapping="Wrap" FontWeight="Bold" FontSize="18" />
                  <TextBlock Text="EA32"  Margin="8,0,0,0" FontSize="14"/>
              </StackPanel>
          </ListBoxItem>
      
          <ListBoxItem Margin="0,300,0,0" Height="120" Width="150" Background="#8000FF00" Foreground="White" BorderThickness="2" BorderBrush="#80000000">
              <StackPanel>
                  <TextBlock Text="Oddanie projektu" Margin="5,0,0,0" Width="130" TextWrapping="Wrap" FontWeight="Bold" FontSize="18" />
                  <TextBlock Text="308"  Margin="8,0,0,0" FontSize="14"/>
              </StackPanel>
          </ListBoxItem>-->
      </ListBox>
      

      具有两个ListBoxItem 项的可视化树:

      在这个例子中一切正常,HeightMargin 属性在代码中设置。

      具有两个Event 项的可视化树:

      在此示例中,您将ItemTemplate 定义为ListBoxItem,但默认情况下ListBox 也会添加容器ListBoxItem,因此您有两个ListBoxItem,这是一个问题,因为您只为内部ListBoxItem。外部ListBoxItem 具有默认属性。

      如果您想自己检查,可以使用此窥探 (http://snoopwpf.codeplex.com/)。

      【讨论】:

      • 像魅力一样工作,谢谢!所以这意味着绑定机制将我的 Event 对象包装在 ListBoxItems 中,我们不应该明确地这样做。
      • @PiotrK 再次检查我的答案,我添加了一些解释。我希望现在更清楚了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多