如何将控件绑定到 WPF 列表视图列

发布于 2024-12-08 18:33:07 字数 1223 浏览 0 评论 0原文

我是 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”的公共字符串属性”和“细节”

到目前为止,一切都很好,一切都很好,但是.. 我希望我的详细信息属性本身就是一个元素(包含各种类型内容的 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
}

I'm new to WPF so forgive me if I've missed something obvious

I have the following list view control (non relevent details removed for brevity)

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

I add items to this list view in code behind

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

where LogEntry has public string properties for "Type" and "Details"

So far, so good, all works lovely but..
I want my details property to be an element itself (TextBox or DockPanel containing various types of content)
How can I bind this Element to the list column?

Using the code above, Changing "Details" to an element I simply get the class name in the list box (e.g. System.Windows.Control.TextBox) as by default the cell displays the ToString() value of the property.
I have googled examples which use a DataTemplate but I can't find an example of binding an element to the content of a panel.
The control cannot be defined in xaml as its structure and contents are not known until runtime

The binding is one way (I only need to display the list, not update the underlying data structure)

To make my problem clearer, I want to bind the following list item

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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

初熏 2024-12-15 18:33:07

您的模型(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}" />

Your Model, the LogEntry class, should not reference a UI control. Instead it should contain the data needed by the UI, and the XAML should define a DataTemplate that uses that data. For example,

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>

You mentioned that the DockPanel in the LogEntry created items that were not known at runtime. Can you give an example of that? In most cases, you should have some kind of pattern in the data, and you can use DataTemplates to define how to draw each Detail piece.

<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>

If you REALLY need to store a control in the Model, then you can use a ContentControl in your DataGridTemplateColumn and set it's Content equal to the Details

<ContentControl Content="{Binding Details}" />
忆离笙 2024-12-15 18:33:07

抱歉,我不能给你一个确切的答案,因为我没有 VS,我现在在这里,但有一些提示。

首先,您不想使用您的方法添加 Listview 项目,而是希望使用您的数据创建 ObservableCollection。然后您可以将列表视图的 itemssource 绑定到 observableCollection。

接下来,您可以为包含所需控件的列表视图创建一个项目模板,非常简单的事情就像具有水平方向和两个文本框的堆栈面板。

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

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

Sorry I cant give you an exact answer as I dont have VS where I am right now here but a few pointers.

First instead of using your method to add Listview items you want to create an ObservableCollection with your data. Then you can bind the itemssource of your listview to the observableCollection.

Next you can create an itemtemplate for the listview containing the control you want, something quite simple would be like a stack panel with horizontal orientation and two textboxes.

Once you have done that because you have set the itemsource of the listview to the ObservableCollection you can just bind the textbox to the String property within your collection.

Note that ObservableCollection is better to bind to than List as ObservableCollection supports NotifyPropertyChanged().

离不开的别离 2024-12-15 18:33:07

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

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>

ViewModel:

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

I have copied your code into a new project and created the same list view here is the code. And this one worked and displayed to data correctly

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>

ViewModel:

 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);
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文