如何在列表框末尾添加自定义文本而不将其添加到使用ItemsSource的apple集合?
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();
}
}
}
您可以使用CollectionView
的占位符特性:它将自动处理占位符项的定位(例如将其固定在末尾或开头)。当在集合上迭代时,这个占位符项不会出现,因此不会污染您的数据结构。
最大的优点是,由于专注于集合视图,您不必修改现有的数据模型及其相关逻辑。
通过将IEditableCollectionView.NewItemPlaceholderPosition
属性设置为NewItemPlaceholderPosition.AtBeginning
或NewItemPlaceholderPosition.AtEnd
来启用占位符项。实现IList
的常见集合(例如ObservableCollection
)由实现IEditableCollectionView
的ListCollectionView
表示。
启用占位符特性后,底层源集合的集合视图现在将包含静态CollectionView.PlaceholderItem
。
你可以为类型为object
的CollectionView.NewItemPlaceholder
创建一个专用的DataTemplate
(底层类型定义为internal
,因此不能被。net库的客户端代码访问)。
自定义DataTemplateSelector
将识别此占位符项以返回相应的DataTemplate
。
占位符项目的DataTemplate
包含一个Button
,允许在单击时添加一个新项目(使用ICommand
或事件处理程序),并显示占位符项目的文本。
FruitTemplateSelector.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),
};
}
MainWindow.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}";
}
MainWindow.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>
有几种方法可以实现这一点。我建议您为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
事件做出反应,并确定它是否来自AddApple
类类型,或者通过在AddApple
中实现的接口中添加一个命令来运行添加新苹果代码,并在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;}
}
将其放在集合中,保持代码与以前基本相同。