如何将ContentControl的内容绑定到ObservableCollection.仅当ObservableColelction包含一个对象(要显示的对象)时,控件才应将对象显示为内容.
谢谢,沃尔特
这很简单.只需使用此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>
Run Code Online (Sandbox Code Playgroud)
这用作ContentControl的ContentTemplate.例如:
<Button Content="{Binding observableCollection}"
ContentTemplate="{StaticResource ShowItemIfExactlyOneItem}" />
Run Code Online (Sandbox Code Playgroud)
这就是你需要做的.
工作原理:模板通常包含一个没有项目的ItemsControl,它是不可见的,没有大小.但是如果设置为Content的ObservableCollection只有一个项目(Count == 1),则触发器会触发并设置ItmesControl的ItemsSource,从而导致单个项目使用面板的Grid显示.Grid模板是必需的,因为默认面板(StackPanel)不允许其内容扩展以填充可用空间.
注意:如果您还想为项目本身指定DataTemplate而不是使用默认模板,请设置ItemsControl的"ItemTemplate"属性.
+1,好问题:)
您可以将 绑定ContentControl到 anObservableCollection<T>并且 WPF 足够聪明,知道您只对渲染集合中的一项(“当前”项)感兴趣
(旁白:这是 WPF 中主从集合的基础,将 ItemsControl 和 ContentControl 绑定到同一个集合,并在 ItemsControl 上设置 IsSynchronizedWithCurrentItem=True)
不过,您的问题询问如何仅ObservableCollection<T>在集合包含单个项目时呈现内容...为此,我们需要利用包含公共财产的事实Count,并明智地使用DataTriggers...
尝试这个...
首先,这是我的简单模型对象“Customer”
public class Customer
{
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在,一个 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; }
}
Run Code Online (Sandbox Code Playgroud)
将窗口中的 DataContext 设置为 VM 的实例...
public Window1()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
Run Code Online (Sandbox Code Playgroud)
有趣的是:使用 XAML 来模板化 Customer 对象,并设置 DataTrigger 以在(且仅当)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>
Run Code Online (Sandbox Code Playgroud)
更新
为了让这种动态行为发挥作用,还有另一个类可以帮助我们......CollectionViewSource
更新您的虚拟机以公开 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);
}
}
Run Code Online (Sandbox Code Playgroud)
在窗口中将按钮单击事件连接到新的“添加”方法(如果您愿意,可以使用命令,这目前同样有效)
private void Button_Click(object sender, RoutedEventArgs e)
{
_viewModel.Add(new Customer { Name = "John Smith" });
}
Run Code Online (Sandbox Code Playgroud)
然后在 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>
Run Code Online (Sandbox Code Playgroud)
现在,您的 ContentControl 的内容是ICollectionView,您可以使用 方法告诉 WPF 当前项目是什么MoveCurrentTo()。请注意,即使 ICollectionView 本身不包含名为“Count”或“Name”的属性,该平台也足够智能,可以在我们的绑定中使用来自 CollectionView 的基础数据源...