【问题标题】:How can I bind a control into a WPF listview column如何将控件绑定到 WPF 列表视图列
【发布时间】:2011-12-02 20:23:33
【问题描述】:

我是 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 具有“类型”和“详细信息”的公共字符串属性

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

使用上面的代码,将“详细信息”更改为一个元素,我只需在列表框中获取类名(例如 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
}

【问题讨论】:

    标签: wpf listview binding


    【解决方案1】:

    您的模型,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 来定义如何绘制每个 Detail 片段。

    <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在运行时决定正确的模板。
    • 谢谢 Rachel,这正是我要找的。有问题的数据是 XML,可以包含文本和/或对象条目的列表。现在我可以将它绑定到面板的内容,我可以考虑各种对象的模板选择器(该项目仍处于早期阶段,所以可能稍后......)
    • @Taoist WPF 实际上可以像绑定到类一样绑定到 XML,所以也许你可以利用它来发挥你的优势。
    【解决方案2】:

    对不起,我无法给你一个确切的答案,因为我现在没有VS,但有一些指针。

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

    接下来你可以为包含你想要的控件的列表视图创建一个itemtemplate,一些非常简单的东西就像一个水平方向和两个文本框的堆栈面板。

    完成此操作后,因为您已将列表视图的 itemsource 设置为 ObservableCollection,您只需将文本框绑定到集合中的 String 属性即可。

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

    【讨论】:

    • 感谢您的回复,我确实考虑按照您建议的方式绑定项目,但我在 add 函数中执行了一些条件突出显示(省略,因为它不会影响我遇到的问题有)我在问题中添加了一些内容,希望能让我的问题更清楚。
    • 没问题,如果没有人回答这个问题,我回家试试看能不能给你答案。关于条件格式,尽管您可以使用我提到的使用样式和触发器的绑定方法来做到这一点。
    【解决方案3】:

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

    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);
     }
    

    【讨论】:

    • 感谢您的回复我也可以使用字符串属性您现在可以使用设置为元素的列表项属性之一,就像我的问题底部的类中一样?这是我遇到的问题
    猜你喜欢
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-09
    • 2011-02-22
    • 2013-11-25
    • 2016-01-06
    相关资源
    最近更新 更多