如何将 ItemsControl 与 WrapPanel 一起使用来列出以逗号分隔的项目?

发布于 2024-11-19 05:49:30 字数 1617 浏览 2 评论 0原文

我有一个 ItemsControl,它通过用逗号分隔来列出项目。代码如下:

<ItemsControl ItemsSource="{Binding MyItems}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text=", " 
                           Name="commaTextBlock"/>
                <TextBlock Text="{Binding}"/>
            </StackPanel>
            <!-- Hide the first comma -->
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding 
                        RelativeSource={RelativeSource PreviousData}}" 
                             Value="{x:Null}">
                    <Setter Property="Visibility" 
                            TargetName="commaTextBlock" 
                            Value="Collapsed"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

结果如下: Item1, Item2, Item3

现在,我想使用 WrapPanel 而不是 StackPanel 作为 ItemsPanelTemplate 来执行相同的操作。我测试了它,它工作正常,除了一个小细节,它执行如下操作:

Item1, Item2

, Item3

当然,这是因为逗号位于每个元素之前,而我隐藏了第一个元素。我想在每个元素后面加上逗号并隐藏最后一个,所以结果将是这样的:

Item1, Item2,

Item3

如果存在像 NextData 这样的东西,那将非常简单(所以我会绑定到这个而不是 PreviousData ),但不幸的是不存在这样的东西(或者我还没有找到)。有谁知道如何解决这个问题?

谢谢

I have an ItemsControl which lists items by separating them with a comma. The code is the following:

<ItemsControl ItemsSource="{Binding MyItems}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text=", " 
                           Name="commaTextBlock"/>
                <TextBlock Text="{Binding}"/>
            </StackPanel>
            <!-- Hide the first comma -->
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding 
                        RelativeSource={RelativeSource PreviousData}}" 
                             Value="{x:Null}">
                    <Setter Property="Visibility" 
                            TargetName="commaTextBlock" 
                            Value="Collapsed"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The result is something like this: Item1, Item2, Item3

Now, I'd like to do the same using a WrapPanel instead of a StackPanel as the ItemsPanelTemplate. I tested it and it works fine, except for a small detail, it does something like this:

Item1, Item2

, Item3

Of course this is because the comma is before each element and I hide the first one. I would like to put the comma after each element and hide the last one, so the result would be this:

Item1, Item2,

Item3

It would be really simple if there existed something like NextData (so I would bind to this instead of to PreviousData), but unfortunately no such thing exists (or I haven't found one). Does anyone have an idea how to solve this problem?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

彡翼 2024-11-26 05:49:30

我已经为类似的问题做了一个可见性转换器:

<TextBlock Text=", " Name="commaTextBlock"> 
   <TextBlock.Visibility>
       <MultiBinding Converter="{StaticResource commaVisibilityConverter}">
       <Binding ElementName="myItemsControl" Path="ItemsSource"/>
       <Binding/>
    </MultiBinding>                            
   </TextBlock.Visibility>
</TextBlock>

转换器逻辑:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var collection = values[0] as IEnumerable<MyItem>;
        var item = values[1] as MyItem;
        if ((collection != null) && (item != null) && (collection.Count() > 0))
        {
            return collection.Last() == item ? Visibility.Hidden : Visibility.Visible;
        }          

        return Visibility.Hidden;
    }

I have done a visibility converter for a similar problem:

<TextBlock Text=", " Name="commaTextBlock"> 
   <TextBlock.Visibility>
       <MultiBinding Converter="{StaticResource commaVisibilityConverter}">
       <Binding ElementName="myItemsControl" Path="ItemsSource"/>
       <Binding/>
    </MultiBinding>                            
   </TextBlock.Visibility>
</TextBlock>

And the converter logic:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var collection = values[0] as IEnumerable<MyItem>;
        var item = values[1] as MyItem;
        if ((collection != null) && (item != null) && (collection.Count() > 0))
        {
            return collection.Last() == item ? Visibility.Hidden : Visibility.Visible;
        }          

        return Visibility.Hidden;
    }
绝影如岚 2024-11-26 05:49:30

也许您可以尝试使用多重绑定和转换器。像这样:

<ItemsControl.ItemTemplate>
  <DataTemplate>
    <TextBlock>
      <TextBlock.Text>
        <MultiBinding Converter="{StaticResource myConverter}">
          <Binding Mode="OneWay"/>
          <Binding ElementName="root" Path="ItemsSource" Mode="OneWay"/>
        </MultiBinding>
      </TextBlock.Text>
    </TextBlock>
  </DataTemplate>
</ItemsControl.ItemTemplate>

其中 root 是 ItemsControl 的名称。

并编写一个检查位置的转换器:

public class MyConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var text = values[0] as string;
        var list = values[1] as ObservableCollection<string>;

        //check for null etc...

        if (list.IndexOf(text) == list.Count - 1)
            return text;

        return string.Format("{0}, ", text);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
       //ignore this, not gonna happen with OneWay Binding 
       return null;
    }
}

对我有用!希望它能帮助您解决您的问题!

编辑
与其他答案几乎相同,这里的区别是您的模板中只需要 1 个 TextBlock ,并且转换器决定是否有逗号。但基本原理是一样的。 MultiBinding 太棒了! :-)

Maybe you can try to use multibinding and a converter. Something like this:

<ItemsControl.ItemTemplate>
  <DataTemplate>
    <TextBlock>
      <TextBlock.Text>
        <MultiBinding Converter="{StaticResource myConverter}">
          <Binding Mode="OneWay"/>
          <Binding ElementName="root" Path="ItemsSource" Mode="OneWay"/>
        </MultiBinding>
      </TextBlock.Text>
    </TextBlock>
  </DataTemplate>
</ItemsControl.ItemTemplate>

Where root is the name of your ItemsControl.

And write a converter which checks for position:

public class MyConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var text = values[0] as string;
        var list = values[1] as ObservableCollection<string>;

        //check for null etc...

        if (list.IndexOf(text) == list.Count - 1)
            return text;

        return string.Format("{0}, ", text);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
       //ignore this, not gonna happen with OneWay Binding 
       return null;
    }
}

Works for me! Hope it helps you with your problem!

EDIT:
Almost the same as the other answer, the difference here is that you only need 1 TextBlock in your template, and the converter decides if there is a comma or not. But basically the same principle. MultiBinding rocks! :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文