如果Count == 1,则将ContentControl绑定到ObservableCollection

Wal*_*ter 6 wpf binding

如何将ContentControl的内容绑定到ObservableCollection.仅当ObservableColelction包含一个对象(要显示的对象)时,控件才应将对象显示为内容.

谢谢,沃尔特

Ray*_*rns 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>
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"属性.


kiw*_*pom 2

+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 的基础数据源...