2010-05-06 13 views
6

Ich versuche, ein Benutzersteuerelement zu schreiben, das über ein ItemsControl verfügt, dessen ItemsTemplate eine TextBox enthält, die TwoWay-Bindung ermöglicht. Allerdings muss ich irgendwo in meinem Code einen Fehler machen, denn die Bindung scheint nur so zu funktionieren, als wäre Mode = OneWay. Dies ist ein ziemlich vereinfachte Auszug aus meinem Projekt, aber es enthält immer noch das Problem:TwoWay-Bindung mit ItemsControl

<UserControl x:Class="ItemsControlTest.UserControl1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="300" Width="300"> 
    <Grid> 
     <StackPanel> 
      <ItemsControl ItemsSource="{Binding Path=.}" 
          x:Name="myItemsControl"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <TextBox Text="{Binding Mode=TwoWay, 
               UpdateSourceTrigger=LostFocus, 
               Path=.}" /> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 
      <Button Click="Button_Click" 
        Content="Click Here To Change Focus From ItemsControl" /> 
     </StackPanel> 
    </Grid> 
</UserControl> 

Hier ist der Code hinter für die obige Steuerung:

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Collections.ObjectModel; 

namespace ItemsControlTest 
{ 
    /// <summary> 
    /// Interaction logic for UserControl1.xaml 
    /// </summary> 
    public partial class UserControl1 : UserControl 
    { 
     public ObservableCollection<string> MyCollection 
     { 
      get { return (ObservableCollection<string>)GetValue(MyCollectionProperty); } 
      set { SetValue(MyCollectionProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for MyCollection. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty MyCollectionProperty = 
      DependencyProperty.Register("MyCollection", 
             typeof(ObservableCollection<string>), 
             typeof(UserControl1), 
             new UIPropertyMetadata(new ObservableCollection<string>())); 

     public UserControl1() 
     { 
      for (int i = 0; i < 6; i++) 
       MyCollection.Add("String " + i.ToString()); 

      InitializeComponent(); 

      myItemsControl.DataContext = this.MyCollection; 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      // Insert a string after the third element of MyCollection 
      MyCollection.Insert(3, "Inserted Item"); 

      // Display contents of MyCollection in a MessageBox 
      string str = ""; 
      foreach (string s in MyCollection) 
       str += s + Environment.NewLine; 
      MessageBox.Show(str); 
     } 
    } 
} 

Und schließlich ist hier das XAML für das Hauptfenster :

<Window x:Class="ItemsControlTest.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:src="clr-namespace:ItemsControlTest" 
     Title="Window1" Height="300" Width="300"> 
    <Grid> 
     <src:UserControl1 /> 
    </Grid> 
</Window> 

Nun, das ist alles. Ich bin mir nicht sicher, warum die Bearbeitung der TextBox.Text-Eigenschaften im Fenster die Quelleigenschaft für die Bindung in dem dahinterliegenden Code, nämlich MyCollection, nicht zu aktualisieren scheint. Ein Klick auf den Button lässt mich ziemlich ins Gesicht schauen;) Bitte hilf mir zu verstehen, wo ich falsch liege.

Danke!

Andrew

Antwort

7

Ok glaube ich, was dieses Problem verursacht wird, dass Sie direkt zu einem String sind verbindlich. Zeichenfolgen sind unveränderlich in C# und wenn Sie den Text ändern, kann es daher die zugrundeliegende Zeichenfolge in dem ObservableCollection nicht ändern. Um dieses Problem zu umgehen, erstellen Sie einfach eine Modellklasse, um die Zeichenfolge Daten zu halten, und binden Sie dann die TextBox.Text an eine Eigenschaft innerhalb der Klasse. Hier ein Beispiel:

public partial class BindingToString : Window 
{ 
    public BindingToString() 
    { 
     MyCollection = new ObservableCollection<TestItem>(); 

     for (int i = 0; i < 6; i++) 
      MyCollection.Add(new TestItem("String " + i.ToString())); 

     InitializeComponent(); 

     myItemsControl.DataContext = this.MyCollection; 
    } 

    public ObservableCollection<TestItem> MyCollection 
    { 
     get; 
     set; 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     // Display contents of MyCollection in a MessageBox 
     string str = ""; 
     foreach (TestItem s in MyCollection) 
      str += s.Name + Environment.NewLine; 
     MessageBox.Show(str); 
    } 
} 

public class TestItem 
{ 
    public string Name 
    { 
     get; 
     set; 
    } 

    public TestItem(string name) 
    { 
     Name = name; 
    } 
} 

Beachten Sie, dass ich Ihre Abhängigkeitseigenschaft zu einem Standard-Eigentums- verändert es keinen Grund ist die Sammlung eine Abhängigkeitseigenschaft zu machen. Abgesehen davon besteht der einzige Unterschied darin, dass die Wrapper-Klasse TestItem die String-Daten enthält.

<Window x:Class="TestWpfApplication.BindingToString" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="BindingToString " Height="300" Width="300"> 
<Grid> 
    <StackPanel> 
     <ItemsControl ItemsSource="{Binding}" 
         x:Name="myItemsControl"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
     <Button Click="Button_Click" 
       Content="Click Here To Change Focus From ItemsControl" /> 
    </StackPanel> 
</Grid> 

Nun ist die TextBox zum Name Weg auf TestItem, und diese Bindung Werke gebunden ist und modifiziert die Sammlung, wie erwartet.

+0

Das ist toll Charlie, sieht aus wie du es genagelt hast. Dein Vorschlag funktioniert gut! – Andrew

Verwandte Themen