2010-05-06 10 views
6

Sto provando a scrivere un controllo utente che abbia un oggetto ItemsControl, il cui ItemTemplate contiene un controllo TextBox che consentirà il binding TwoWay. Tuttavia, devo commettere un errore da qualche parte nel mio codice, perché il collegamento sembra funzionare come se Mode = OneWay. Questo è un estratto piuttosto semplificata dal mio progetto, ma contiene ancora il problema:TwoWay Binding With 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> 

Ecco il codice dietro per il controllo di cui sopra:

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

E, infine, ecco il codice XAML per la finestra principale :

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

Bene, questo è tutto. Non sono sicuro del motivo per cui modificare le proprietà TextBox.Text nella finestra non sembra aggiornare la proprietà source per il binding nel codice sottostante, ovvero MyCollection. Fare clic sul pulsante fa sì che il problema mi guardi in faccia;) Per favore aiutami a capire dove sto andando male.

Grazie!

Andrew

risposta

7

Ok Credo che cosa sta causando il problema è che si desidera associare direttamente a un String. Le stringhe sono immutable in C# e quindi quando si modifica il testo, non è possibile modificare la stringa sottostante in ObservableCollection. Quello che puoi fare per aggirare questo problema è semplicemente creare una classe modello per contenere i dati di stringa, e quindi associare a una proprietà all'interno di quella classe. Ecco un esempio:

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

Si noti che ho cambiato la vostra proprietà di dipendenza a una proprietà-serie non v'è alcun motivo per fare la raccolta una proprietà di dipendenza. Inoltre, l'unica differenza è l'inclusione della classe wrapper TestItem per contenere i dati di stringa.

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

Ora il TextBox è legato al percorso Name su TestItem, e funziona questo legame e modifica la raccolta come previsto.

+0

Che bello Charlie, sembra che l'hai inchiodato. Il tuo suggerimento funziona bene! – Andrew