2017-03-21 3 views
3

Okay, Entschuldigung für meine vorherige Unordnung.Wie ItemsSource-Eigenschaft zuweisen

Die Situation ist folgende: Ich habe zwei benutzerdefinierte Objekte wie folgt definiert: MainObject:

public class MainObject 
{ 
    private string mainObjectName; 
    public string MainObjectName { get { return mainObjectName; } } 

    private List<SubObject> subObjectData; 
    public List<SubObject> SubObjectData { get { return subObjectData; } } 

    public MainObject(string name, List<SubObject> objectData) 
    { 
     mainObjectName = name; 
     subObjectData = objectData; 
    } 
} 

SUBOBJECT:

public class SubObject 
{ 
    private string subObjectName; 
    public string SubObjectName { get { return subObjectName; } } 

    private List<int> integerData; 
    public List<int> IntegerData { get { return integerData; } } 

    public SubObject(string name, List<int> data) 
    { 
     subObjectName = name; 
     integerData = data; 
    } 
} 

Ich habe auch ein Ansichtsmodell, das der Einfachheit halber einige Daten definiert mit diese zwei Objekte wie folgt: VM

public List<Model.MainObject> VMList = new List<Model.MainObject>() 
    { 
     new Model.MainObject("MainItem1", new List<Model.SubObject>() 
     { 
      new Model.SubObject("SubItem1", new List<int>() { 1,6,3}), 
      new Model.SubObject("SubItem2", new List<int>() { 5,2,9}) 
     }), 
     new Model.MainObject("MainItem2", new List<Model.SubObject>() 
     { 
      new Model.SubObject("SubItem1", new List<int>() { 0,3,1}), 
      new Model.SubObject("SubItem2", new List<int>() { 7,5,2}) 
     }) 
    }; 

jetzt habe ich die folgenden UI-

<Grid> 
    <ItemsControl Name="MainObjectIC"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Grid> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition/> 
         <ColumnDefinition/> 
        </Grid.ColumnDefinitions> 
        <TextBlock Text="{Binding MainObjectName}"/> 
        <ItemsControl Name="SubObjectIC"> 
         <ItemsControl.ItemTemplate> 
          <DataTemplate> 
           <TextBlock Text="{Binding SubObjectName}"/> 
          </DataTemplate> 
         </ItemsControl.ItemTemplate> 
        </ItemsControl> 
       </Grid> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Grid> 

ich die Itemssource des MainObjectIC im Code zuweisen hinter etwa so:

ViewModel.VM dc = new ViewModel.VM(); 

    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = dc; 
     MainObjectIC.ItemsSource = dc.VMList; 
    } 

Ich möchte auch, aber die Itemssource zum SubObjectIC zuweisen, dass ich zu tun muss das ItemsControl Objekt holen. Und das versuche ich zu erreichen.

Von dem, was ich verstanden habe, kann es sehr, sehr schlecht und nutzlos sein, die ItemsSource-Eigenschaft aus dem Code hinter zu zuweisen.

+0

Ich denke, eine relative Quelle für die Bindung für die "Kind" Sammlung sollte funktionieren. Ich habe das nur getan, um den Ahnen-Typ des Fensters zu finden, aber ich denke, dass es viel mehr Typen erlauben wird. –

+0

gibt es '{Binding ...}', das über das Markup hinweg bindet. Warum ItemsSource für 'RelicItemsSource' kann nicht an XAML gebunden werden? – ASh

+0

ja, aber ich habe keine Ahnung, wie es geht, da die RelicItemsSource von dem Objekt abhängen sollte, das an die ComponentsItemsSource gebunden ist. Außerdem denke ich, dass ich den DataContext an dieses anstatt an mein custome Objekt binden muss. –

Antwort

2

Vielen Dank für die Verbesserung Ihres Codebeispiels. Es war immer noch nicht vollständig, aber es ist nahe genug, um eine Antwort geben zu können.

In Ihrem Beispiel ist die Hauptsache, die fehlt, einfach den notwendigen Ausdruck {Binding} hinzuzufügen. Insbesondere gilt Folgendes:

<ItemsControl Name="SubObjectIC" Grid.Column="1" 
       ItemsSource="{Binding SubObjectData}"> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <TextBlock Text="{Binding SubObjectName}"/> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Der Kontext für den Artikel ist bereits ein Objekt vom Typ MainObject (weshalb Ihre TextBlock Bindung Werke sind). Alles, was noch zu tun bleibt, ist, die Eigenschaft ItemsSource an die Eigenschaft MainObject.SubObjectData zu binden.

(ich hatte die Grid.Column Zuordnung, die von Ihrem Beispiel oben zu fehlen schien hinzuzufügen.)

Die obige Änderung Ihr Beispiel zu bekommen völlig ausreichend ist, wie Sie arbeiten wollen. Sie können den Code jedoch auch verbessern, indem Sie denselben grundlegenden Ansatz für das Steuerelement auf oberster Ebene verwenden. Um dies zu tun, Ihr VM.VMList Feld geändert werden muss eine Eigenschaft zu sein (WPF bindet nur an Eigenschaften, nicht Felder):

class VM 
{ 
    public List<MainObject> VMList { get { return _vmList; } } 

    private readonly List<MainObject> _vmList = new List<MainObject>() 
    { 
     new MainObject("MainItem1", new List<SubObject>() 
     { 
      new SubObject("SubItem1", new List<int>() { 1,6,3}), 
      new SubObject("SubItem2", new List<int>() { 5,2,9}) 
     }), 
     new MainObject("MainItem2", new List<SubObject>() 
     { 
      new SubObject("SubItem1", new List<int>() { 0,3,1}), 
      new SubObject("SubItem2", new List<int>() { 7,5,2}) 
     }) 
    }; 
} 

Dann können Sie nur die explizite Zuordnung entfernen, die in Ihrem Konstruktor ist:

public MainWindow() 
{ 
    InitializeComponent(); 
    DataContext = dc; 
} 

Mit diesen Änderungen, XAML muss nicht mehr jede der Kontrollen Namen geben, und Sie können direkt auf die relevanten Eigenschaften binden:

<Window x:Class="TestSO42929995WpfNestedData.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:TestSO42929995WpfNestedData" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
    <ItemsControl ItemsSource="{Binding VMList}"> 
     <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition/> 
       <ColumnDefinition/> 
      </Grid.ColumnDefinitions> 
      <TextBlock Text="{Binding MainObjectName}"/> 
      <ItemsControl Grid.Column="1" 
          ItemsSource="{Binding SubObjectData}"> 
       <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBlock Text="{Binding SubObjectName}"/> 
       </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 
      </Grid> 
     </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
    </Grid> 
</Window> 

Ein Schlüssel poi Das ist vielleicht nicht offensichtlich, da jedes Steuerelement einen DataContext hat. Wenn Sie die {Binding}-Syntax verwenden, ist der Eigenschaftenpfad standardmäßig relativ zu diesem Kontext. Im Steuerelement der obersten Ebene wird der Kontext so festgelegt, dass er im Konstruktor festgelegt wird.In der individuellen Listenelementvorlage ist der Kontext jedoch das individuelle Datenobjekt für diesen Listeneintrag, in Ihrem Fall das Objekt MainObject. In diesem Kontext binden Sie einfach an die Eigenschaft SubObjectData, genau wie Sie an die MainObjectName binden. Es funktioniert genau so und aus dem gleichen Grund.

+0

Oh, Gott bitte töte mich, ich bin so ein Idiot. Vielen Dank für die Zeit verschwendet –

+0

@George: keine Notwendigkeit, so schwer auf sich selbst zu sein. Wenn du wirklich ein Idiot wärst, wärst du nicht empfänglich für Feedback über deinen ursprünglichen Beitrag und wie du ihn verbessern kannst (glaube mir, es gibt viele solcher Leute auf Stack Overflow). Und während ich vermute, dass es _similar_ Fragen auf Stack Overflow gibt, suchte ich nach, fand aber keine, die ganz genau wie Ihre waren. Und selbst wenn, dann hat dieser hier ein gutes, einfaches Codebeispiel, um sowohl die Frage als auch die Antwort zu illustrieren, was kaum wie eine Zeitverschwendung erscheint. :) –

+0

Danke für die Unterstützung und tolle Einstellung :) –