如何将控件绑定到WPF ListView列中

3

我是WPF的新手,如果我漏掉了一些显而易见的东西,请原谅。

我有以下列表视图控件(为简洁起见删除了非相关细节)

<ListView>
  <ListView.View>
    <GridView>
      <GridViewColumn Header="Type" DisplayMemberBinding="{Binding Type}"/>
      <GridViewColumn Header="Details" DisplayMemberBinding="{Binding Details}"/>
    </GridView>
  </ListView.View>
</ListView>

我在代码后台添加项目到这个列表视图中。

public void Add(LogEntry entry)
{
  ListViewItem item = new ListViewItem();
  item.Content = entry;
  listView.Items.Add(item);
}

LogEntry拥有公共字符串属性"Type"和"Details"

到目前为止,一切都很好,但是... 我希望我的Details属性本身就是一个元素(TextBox或DockPanel包含不同类型的内容) 我该如何将此元素绑定到列表列?

使用上述代码,将“Details”更改为元素后,我只会在列表框中得到类名(例如System.Windows.Control.TextBox),因为单元格默认显示属性的ToString()值。 我已经谷歌了一些示例,它们使用了DataTemplate,但我找不到将元素绑定到面板内容的示例。 该控件无法在xaml中定义,因为其结构和内容直到运行时才知道

绑定是单向的(我只需要显示列表,而不需要更新底层数据结构)

为了让我的问题更清楚,我想绑定以下列表项

class LogEntry
{
  public string Type {get;}
  public DockPanel Details {get;} // This dock panel was created by code and contains
                                  // various elements not predictable at compile time
}
3个回答

0

我已将您的代码复制到一个新项目中,并创建了相同的列表视图,以下是代码。这个代码可以正常工作并正确显示数据

XAML:

 <ListView x:Name="MyList" ItemsSource="{Binding MyListDetails}">
    <ListView.View>
      <GridView>
         <GridViewColumn Header="Type" DisplayMemberBinding="{Binding Firstname}"/>
         <GridViewColumn Header="Details" DisplayMemberBinding="{Binding Lastname}"/>
      </GridView>
 </ListView.View>

视图模型:

 private List<Contact> _details= new List<Contact>();;
    public List<Contact> MyListDetails
    {
        get
        {
            return _details;
        }
        set
        {
            _details = value;
            this.RaisePropertyChanged("MyListDetails");
        }
    }

 public void AddEntry(LogEntry entry)
 {
   MyListDetails.Add(entry);
 }

谢谢您的回复。 我也用字符串属性实现了这个。 现在,您能否将其设置为列表项属性之一,例如我问题底部的类中所示? 这就是我遇到的问题。 - Taoist

0

你的模型,即LogEntry类,不应该引用UI控件。相反,它应该包含UI所需的数据,而XAML应该定义一个使用该数据的DataTemplate。例如:

public class LogEntry
{
  public string Type {get;}
  public ObservableCollection<IDetail> Details {get;}
}

<DataGridTemplateColumn Header="Details">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <DockPanel>
                <ItemsControl ItemsSource="{Binding Details}" />
            </DockPanel>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

您提到在 LogEntry 中的 DockPanel 创建了一些在运行时未知的项。能否举个例子呢?在大多数情况下,您应该在数据中有某种模式,并可以使用 DataTemplates 来定义如何绘制每个详细信息。

<DataTemplate DataType="{x:Type local:LoginDetail}}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding CreatedDate}" />
        <TextBlock Text="{Binding UserName}" />
        <TextBlock Text="{Binding MachineLoggedIn}" />
    </StackPanel>
</DataTemplate>

<DataTemplate DataType="{x:Type local:LogoutDetail}}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding CreatedDate}" />
        <TextBlock Text="{Binding UserName}" />
        <TextBlock Text="{Binding LoggedInTime}" />
    </StackPanel>
</DataTemplate>

如果您确实需要将控件存储在模型中,那么您可以在DataGridTemplateColumn中使用ContentControl,并将其Content设置为详细信息。
<ContentControl Content="{Binding Details}" />

我同意你的答案。从模型绑定到控件是一种不好的做法。道士应该使用DataTemplatesDataTemplateSelector在运行时决定正确的模板。 - Miklós Balogh
谢谢Rachel,这正是我在寻找的。所涉及的数据是XML,可以包含文本和/或对象条目列表。现在我可以将其绑定到面板的内容上,我可以考虑为各种对象使用模板选择器(项目仍处于早期阶段,所以也许稍后会...)。 - Taoist
@Taoist WPF实际上可以像绑定到类一样绑定到XML,因此也许您可以利用这一点。 - Rachel

0

抱歉,我无法给你一个确切的答案,因为我现在所在的地方没有VS,但是我可以给你一些指针。

首先,你需要创建一个ObservableCollection来存储你的数据,而不是使用你的方法来添加Listview项。然后,你可以将listview的itemssource绑定到observableCollection。

接下来,你可以为listview创建一个itemtemplate,其中包含你想要的控件,比如一个水平方向的stack panel和两个文本框。

一旦你完成了这些步骤,因为你已经将listview的itemsource设置为ObservableCollection,你只需要将文本框绑定到你集合中的字符串属性即可。

请注意,ObservableCollection比List更适合绑定,因为ObservableCollection支持NotifyPropertyChanged()。


谢谢回复。我确实考虑过按照您建议的方式绑定项目,但是在添加函数中进行了一些条件高亮显示(由于它不影响我遇到的问题,因此被省略了)。我已经在问题中添加了更多内容,希望能够更清楚地说明我的问题。 - Taoist
没问题,如果没有人回答,我会在回家后尝试并看看能否给你一个答案。关于条件格式的问题,你可以使用我提到的绑定方法,使用样式和触发器来实现。 - Purplegoldfish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接