wpf 如何向ItemsControl添加占位符项?

fslejnso  于 2022-12-24  发布在  其他
关注(0)|答案(2)|浏览(300)

如何在列表框末尾添加自定义文本,而不使用ItemsSource将其添加到apples集合?

e.g.
Listbox:
Listbox Item1-Apple
Listbox Item2-Apple
Listbox Item3-Apple.. Could be more or less Apple the last item should say "ADD NEW..."
Listbox Item4-ADD NEW...

XAML:

<Grid>
    <ListBox Name="lbxFruits" Margin="0,0,70,52">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation = "vertical" Background="Green">
                    <Label>Hello</Label>
                    <TextBlock Text = "{Binding Price, ElementName=lbxFruits}" Width = "14" />

                    <TextBlock Text = "{Binding Name, ElementName=lbxFruits}" />

                </StackPanel >
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button Content="Button" HorizontalAlignment="Left" Margin="690,404,0,0" VerticalAlignment="Top" Click="Button_Click"/>
</Grid>

C编号:

private void RebuildList()
{
    ListBoxItem addItem = new ListBoxItem() { Content = "ADD NEW ..." };
    lbxFruits.ItemsSource = apples;
}

private ObservableCollection<Fruit> apples ;
public ObservableCollection<Fruit> Apples
{
    get
    {
        return this.apples;
    }

    set
    {
        if (value != this.apples)
        {
            this.apples = value;
            NotifyPropertyChanged();
        }
    }
}
ct2axkht

ct2axkht1#

您可以使用CollectionView的占位符功能:它会自动处理占位符项的位置(例如将其固定在末尾或开头)。当遍历集合时,此占位符项不会出现,因此不会污染数据结构。
最大的优点是,由于集中在集合视图上,因此不必修改现有的数据模型及其相关逻辑。
通过将IEditableCollectionView.NewItemPlaceholderPosition属性设置为NewItemPlaceholderPosition.AtBeginningNewItemPlaceholderPosition.AtEnd,可以启用占位符项。实现IList(例如ObservableCollection)的公共集合由实现IEditableCollectionViewListCollectionView表示。
启用占位符特性后,基础源集合的集合视图现在将包含静态CollectionView.PlaceholderItem
然后,您可以为CollectionView.NewItemPlaceholder创建一个专用的DataTemplate,其类型为object(基础类型定义为internal,因此.NET库的客户端代码无法访问)。
然后,定制的DataTemplateSelector将标识此占位符项以返回适当的DataTemplate
占位符项的DataTemplate包含一个Button,它允许在单击时添加新项(使用ICommand或事件处理程序)并显示占位符项的文本。

水果模板选择器.cs

public class FruitTemplateSelector : DataTemplateSelector
{
  /* Add more template properties in case you have more data types */

  public DataTemplate AppleTemplate { get; set; }
  public DataTemplate PlaceholderTemplate { get; set; }

  public override DataTemplate SelectTemplate(object item, DependencyObject container) => item switch
  {
    var dataItem when dataItem == CollectionView.NewItemPlaceholder => this.PlaceholderTemplate,
    Apple _ => this.AppleTemplate,
    _ => base.SelectTemplate(item, container),
  };
}

主窗口.xaml.cs

partial class MainWindow : Window
{
  public ObservableCollection<string> TextItems { get; }

  public MainWindow()
  {
    InitializeComponent();
    this.DataContext = this;
 
    this.TextItems = new ObservableCollection<string>
    {
      "Item #1",
      "Item #2",
      "Item #3"
    };

    // Get the default collection view of the source collection
    ICollectionView textItemsView = CollectionViewSource.GetDefaultView(this.TextItems);

    // Enable the placeholder item 
    // and place it at the end of the collection view
    IEditableCollectionView editableCollectionView = textItemsView as IEditableCollectionView;
    editableCollectionView.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtEnd;
  }

  private void AddNewItem_OnClick(object sender, EventArgs e)
    => this.TextItems.Add($"Item #{this.TextItems.Count + 1}";
}

主窗口.xaml

<Window xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <ListBox ItemsSource="{Binding TextItems}"
           HorizontalContentAlignment="Stretch">
    <ListBox.ItemTemplateSelector>
      <local:FruitTemplateSelector>
        <local:FruitTemplateSelector.AppleTemplate>
          <DataTemplate DataType="{x:Type sys:String}">
            <TextBlock Text="{Binding}" />
          </DataTemplate>
        </local:FruitTemplateSelector.AppleTemplate>

        <local:FruitTemplateSelector.PlaceholderTemplate>
          <DataTemplate>
            <Button Content="Add New Item..."
                    Click="AddNewItem_OnClick"
                    Background="Orange" />
          </DataTemplate>
        </local:FruitTemplateSelector.PlaceholderTemplate>
      </local:FruitTemplateSelector>
    </ListBox.ItemTemplateSelector>
  </ListBox>
</Window>
xwbd5t1u

xwbd5t1u2#

有几种方法可以实现这一点,我建议您为Fruit定义一个接口,并让ObservableCollection包含一个实现该接口的类示例列表,如下所示:

interface IFruit
{
  string Name{get;set;}
  string Price{get;set;}
}

class Apple:IFruit
{
  string Name{get;set;}
  string Price{get;set;}
}

class AddApple:IFruit
{
  string Name{get;set;} = "Add New Apple";
  string Price{get;set;}
}

public ObservableCollection<IFruit> Apples

然后你只需要触发你的代码来添加一个新的Apple,或者通过对OnClick事件做出React并确定它是否来自AddApple类类型,或者通过向在AddApple中实现的接口添加一个命令来运行add new apple代码,在Apple类中添加一个命令来做其他事情(或者什么都不做)。
事实上,您可以将该接口添加到Fruit类,因为我假设Apple继承自它。
例如,

abstract class Fruit : IFruit
{
  public virtual string Name{get;set;}
  public virtual string Price{get;set;}
}

class Apple : Fruit
{
    public override string Name { get; set; } = "Apple"
    public override string Price { get; set; }
}

然后,您可以为从Fruit继承的所有类型使用类似的代码。
或者您只需:

class NewApple : Fruit
{
  public override string Name{get;set;} = "Add New Apple";
  public override string Price{get;set;}
}

将它放在集合中,保持代码与以前基本相同。

相关问题