如何将ContentControl的内容绑定到ObservableCollection。 仅当ObservableColelction包含一个对象(要显示的对象)时,控件才应将对象显示为内容。
谢谢, 沃尔特
答案 0 :(得分:6)
这很容易。只需使用此DataTemplate:
<DataTemplate x:Key="ShowItemIfExactlyOneItem">
<ItemsControl x:Name="ic">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><Grid/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Count}" Value="1">
<Setter TargetName="ic" Property="ItemsSource" Value="{Binding}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
这用作ContentControl的ContentTemplate。例如:
<Button Content="{Binding observableCollection}"
ContentTemplate="{StaticResource ShowItemIfExactlyOneItem}" />
这就是你需要做的一切。
工作原理:模板通常包含一个没有项目的ItemsControl,它是不可见的,没有大小。但是如果设置为Content的ObservableCollection只有一个项目(Count == 1),则触发器会触发并设置ItmesControl的ItemsSource,从而导致单个项目使用面板的Grid显示。 Grid模板是必需的,因为默认面板(StackPanel)不允许其内容扩展以填充可用空间。
注意:如果您还想为项目本身指定DataTemplate而不是使用默认模板,请设置ItemsControl的“ItemTemplate”属性。
答案 1 :(得分:2)
+1,好问题:)
您可以将ContentControl
绑定到ObservableCollection<T>
,WPF足够聪明,知道您只对从集合中呈现一个项目感兴趣(“当前”项目)
(旁白:这是WPF中主 - 细节集合的基础,将ItemsControl和ContentControl绑定到同一个集合,并在ItemsControl上设置IsSynchronizedWithCurrentItem = True)
但是,您的问题是,如果集合包含单个项目,则询问如何仅呈现内容 ...为此,我们需要利用ObservableCollection<T>
包含公众的事实Count
属性,以及对DataTriggers
...
试试这个......
首先,这是我的琐碎模型对象,'客户'
public class Customer
{
public string Name { get; set; }
}
现在,一个ViewModel公开了这些对象的集合......
public class ViewModel
{
public ViewModel()
{
MyCollection = new ObservableCollection<Customer>();
// Add and remove items to check that the DataTrigger fires correctly...
MyCollection.Add(new Customer { Name = "John Smith" });
//MyCollection.Add(new Customer { Name = "Mary Smith" });
}
public ObservableCollection<Customer> MyCollection { get; private set; }
}
将Window中的DataContext设置为VM的实例...
public Window1()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
这里有趣的是:XAML模拟Customer对象,并设置DataTrigger以删除'Invalid Count'部分,如果(且仅当)Count等于1。
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate x:Name="template">
<Grid>
<Grid Background="AliceBlue">
<TextBlock Text="{Binding Name}" />
</Grid>
<Grid x:Name="invalidCountGrid" Background="LightGray" Visibility="Visible">
<TextBlock
VerticalAlignment="Center" HorizontalAlignment="Center"
Text="Invalid Count" />
</Grid>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Count}" Value="1">
<Setter TargetName="invalidCountGrid" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<ContentControl
Margin="30"
Content="{Binding MyCollection}" />
</Window>
<强> 更新 强>
为了让这种动态行为有效,还有另一个类可以帮助我们...... CollectionViewSource
更新您的VM以公开ICollectionView,例如:
public class ViewModel
{
public ViewModel()
{
MyCollection = new ObservableCollection<Customer>();
CollectionView = CollectionViewSource.GetDefaultView(MyCollection);
}
public ObservableCollection<Customer> MyCollection { get; private set; }
public ICollectionView CollectionView { get; private set; }
internal void Add(Customer customer)
{
MyCollection.Add(customer);
CollectionView.MoveCurrentTo(customer);
}
}
并在窗口中点击一个按钮点击事件直到新的“添加”方法(如果您愿意,可以使用命令,这在目前同样有效)
private void Button_Click(object sender, RoutedEventArgs e)
{
_viewModel.Add(new Customer { Name = "John Smith" });
}
然后在XAML中,根本不更改资源 - 将其作为窗口的主体:
<StackPanel>
<TextBlock Height="20">
<TextBlock.Text>
<MultiBinding StringFormat="{}Count: {0}">
<Binding Path="MyCollection.Count" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<Button Click="Button_Click" Width="80">Add</Button>
<ContentControl
Margin="30" Height="120"
Content="{Binding CollectionView}" />
</StackPanel>
现在,您的ContentControl的内容是ICollectionView
,您可以使用MoveCurrentTo()
方法告诉WPF当前项目是什么。
请注意,即使ICollectionView本身不包含名为“Count”或“Name”的属性,该平台也足够智能,可以在我们的Bindings中使用CollectionView中的基础数据源...