2016-04-21 5 views
0

Ich sehe, dass im Laufe der Jahre viele Fragen gestellt wurden, wie man am besten mit Daten innerhalb eines Datatemplate bindet, gibt es eine Best Practice? In diesem Fall möchte ich mit MemoryCopyBtn den Text der aktuell ausgewählten MemoryListItem TextBox kopieren, damit ich im ViewModel daran arbeiten kann.Best Practice für das Binden von Eigenschaften von Steuerelementen in einem DataTemplate?

Ich kann die ListView mit Findname finden, aber es wird Null für ein ListViewItem in PageLoad angezeigt.

Ich kann alles in die Memory-Modell-Seite einfügen, aber ich denke nicht, dass das beste Verfahren ist.

Ich sehe, dass das verschiedene Optionen sind, um den visuellen Codebaum zu gehen, aber ich möchte dies während der Laufzeit tun, ist das wirklich der einzige Weg?

Was sind meine Optionen? Danke.

<ListView x:Name="ClipboardList" 
         xmlns:m="using:QuickieEdit.Models" 
         ItemsSource="{x:Bind ViewModel.MemoryItems}"> 
       <ListView.ItemTemplate> 
        <DataTemplate x:DataType="m:MemoryItem"> 
          <StackPanel Orientation="Horizontal"> 
           <Button x:Name="MemoryCopyBtn" 
              Content="Copy" 
              Click="How to Copy currently selected 
              MemoryListItem.Text?"/> 
           <TextBox x:Name="MemoryListItem" 
               Text="{x:Bind Memory, Mode=TwoWay}"> 
           </TextBox>         
          </StackPanel> 
        </DataTemplate> 
       </ListView.ItemTemplate> 
</ListView> 
+0

Auf Knopfdruck möchten Sie Text in TextBox, die in der gleichen DataTemplate ist kopieren? – Evk

+0

Ja. Ich möchte den aktuell ausgewählten oder fokussierten ListViewItem TextBox.Content kopieren. –

Antwort

1

Wenn ich Sie richtig verstehe - Sie Text der Textbox kopieren möchten, die zusammen mit der Schaltfläche, die Sie klicken, nicht einige ausgewählte \ fokussierte Textbox befindet (sonst macht das keinen Sinn, weil Sie eine Schaltfläche zum Kopieren für jedes Element haben in Ihrer Listenansicht). Wenn ja, nur Befehl verwenden:

<ListView.ItemTemplate> 
     <DataTemplate x:DataType="m:MemoryItem"> 
      <StackPanel Orientation="Horizontal"> 
       <Button x:Name="MemoryCopyBtn" 
         Content="Copy" 
         Command="{Binding CopyCommand}" 
         CommandParameter="{Binding ElementName=MemoryListItem, Path=Text}" /> 
       <TextBox x:Name="MemoryListItem" 
         Text="{x:Bind Memory, Mode=TwoWay}"></TextBox> 
      </StackPanel> 
     </DataTemplate> 
    </ListView.ItemTemplate> 

Und in Ihrem MemoryItem:

public class MemoryItem { 
    public MemoryItem() { 
     CopyCommand = new RelayCommand(Copy); 
    }   

    public string Memory { get; set; } 
    public ICommand CopyCommand { get; private set; } 

    private void Copy(object argument) 
    { 
     var text = (string)argument; 
     Console.WriteLine(text); 
    } 
} 
+0

Das bedeutet, dass Sie eine Instanz von RelayCommand für jedes Element in der Liste erstellen. Keine der besten Lösungen in Bezug auf Skalierbarkeit. – DHN

+0

@DHN Instanz von ICommand pro Element hat absolut keinen Effekt auf Skalierbarkeit und Leistung. – Evk

+0

Interessant, Sie verbrauchen Speicher mit jeder Instanz, nicht wahr? – DHN

0

Wenn Sie rein x verwenden möchten: Bind, empfehle ich Ihnen das Click-Ereignis in XAML definieren, Click="onButtonClicked". In der Ansicht rufen Sie das ViewModel auf (in MVVM kennt die View die VM) ODER Sie können eine Nachricht veröffentlichen, das ViewModel fängt es ab und erledigt die Arbeit. MVVM Light hat diesen Messenger-Mechanismus.

+0

Ob ich das ListViewItem im ViewModel mit FindName oder im Code der View mit SelectionChanged oder im Textfeld selbst mit GetFocus aufruft, der ListviewItem.Content kommt immer null zurück. Ich denke, das, wonach ich suche, ist eine Best Practice, um den Inhalt des aktuell ausgewählten oder fokussierten ListViewItems zurückzugeben. –

+0

Mit Inhalt meinen Sie das Objekt, das an das Listenansichtselement gebunden ist, oder den XAML-Inhalt des Listenansichtselements?Wenn Sie auf das Objekt zugreifen möchten, können Sie es über den 'DataContext' des Senderobjekts im Event-Handler abrufen. Sie können auch x: Bind verwenden, um an den Ereignishandler in Ihrem ViewModel zu binden, sodass Sie das Ereignis in der Ansicht nicht mehr behandeln müssen. – thang2410199

1

ich glaube, Sie das Click-Ereignis der Schaltfläche in Ihrem MemoryItem binden können, dann können Sie den Datenkontext des geklickten erhalten Schaltfläche in diesem Ereignis.

Just for Test, schrieb ich eine sehr einfache Demo hier:

<ListView x:Name="ClipboardList" ItemsSource="{x:Bind ViewModel.MemoryItems}"> 
    <ListView.ItemTemplate> 
     <DataTemplate x:DataType="local:MemoryItem"> 
      <StackPanel Orientation="Horizontal"> 
       <Button x:Name="MemoryCopyBtn" 
            Content="Copy" 
            Click="{x:Bind MemoryCopyBtn_Click}" /> 
       <TextBox x:Name="MemoryListItem" 
             Text="{x:Bind Memory, Mode=TwoWay}"> 
       </TextBox> 
      </StackPanel> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

-Code hinter:

private MainPageViewModel ViewModel; 

public MainPage() 
{ 
    this.InitializeComponent(); 
    ViewModel = new MainPageViewModel(); 
} 

Meine MainPageViewModel Klasse:

public class MainPageViewModel 
{ 
    public ObservableCollection<MemoryItem> MemoryItems; 

    public MainPageViewModel() 
    { 
     MemoryItems = new ObservableCollection<MemoryItem>(); 
     MemoryItems.Clear(); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 1" }); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 2" }); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 3" }); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 4" }); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 5" }); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 6" }); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 7" }); 
     MemoryItems.Add(new MemoryItem { Memory = "Item 8" }); 
    } 
} 

Die MemoryItem Klasse:

public class MemoryItem 
{ 
    public string Memory { get; set; } 

    public void MemoryCopyBtn_Click(object sender, RoutedEventArgs e) 
    { 
     var item = ((FrameworkElement)e.OriginalSource).DataContext as MemoryItem; 
     var text = item.Memory; 
    } 
} 

Dieser Code hier ist nicht 100% identisch mit Ihnen, sehr einfach nur für den Test, bitte nichts dagegen. In den meisten Fällen vermeiden wir die Verwendung von VisualTree Helper für diese Arbeit, x: Bind kann für Ereignisse verwendet werden, hier ist es sehr nützlich.

+0

Danke Grace Feng. Ich entschied mich, mit Evks Befehl unten zu gehen, hauptsächlich weil ich das Kommando benutzen wollte, aber ich schätze deine Hilfe! –