开发者

How can I bind a control into a WPF listview column

开发者 https://www.devze.com 2023-04-11 15:19 出处:网络
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)

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
}


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}" />


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().


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号