5

. İlk başlangıçta uygulama başlangıcında ciltleme işleri (dönüştürücü). Bağlanan koleksiyona yapılan Değişiklikler, Temizle() veya Ekle(), TabControl ... dönüştürücüsüne yansıtılmaz.Silverlight TabControl, koleksiyonun değiştiğinde güncellenemeyen ObservableCollection <string>'a bağlanmadı. Bir IValueConverter kullanarak bir ObservableCollection'a bağlı bir TabControl ile Silverlight 3 uygulaması

not: Bağlı ListBox, TabControl yokken bağlı koleksiyondaki değişiklikleri yansıtır.

Fikirler? bağlayıcı

/JHD


XAML ...

<UserControl.Resources> 
    <local:ViewModel x:Key="TheViewModel"/> 
    <local:TabConverter x:Key="TabConverter" /> 
</UserControl.Resources> 
<StackPanel DataContext="{StaticResource TheViewModel}"> 
    <ListBox ItemsSource="{Binding Classnames}" /> 
    <controls:TabControl x:Name="TheTabControl" 
     ItemsSource="{Binding Classnames, Converter={StaticResource TabConverter}, ConverterParameter=SomeParameter}"/> 
    <Button Click="Button_Click" Content="Change ObservableCollection" /> 
</StackPanel> 

ViewModel ...

namespace DatabindingSpike 
{ 
    public class ViewModel 
    { 
     private ObservableCollection<string> _classnames = new ObservableCollection<string>(); 

     public ViewModel() 
     { 
      _classnames.Add("default 1 of 2"); 
      _classnames.Add("default 2 of 2"); 
     } 

     public ObservableCollection<string> Classnames 
     { 
      get { return _classnames; } 
      set { _classnames = value; } 
     } 
    } 
} 
(Şeyiyle)

dönüştürücü ...

namespace DatabindingSpike 
{ 
    public class TabConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      var source = value as ObservableCollection<string>; 
      if (source == null) 
       return null; 

      var param = parameter as string; 
      if (string.IsNullOrEmpty(param) || param != "SomeParameter") 
       throw new NotImplementedException("Null or unknow parameter pasased to the tab converter"); 

      var tabItems = new List<TabItem>(); 
      foreach (string classname in source) 
      { 
       var tabItem = new TabItem 
            { 
             Header = classname, 
             Content = new Button {Content = classname} 
            }; 
       tabItems.Add(tabItem); 
      } 

      return tabItems; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 
+0

olma ihtimali nedir? Modu açık bir şekilde ayarlamayı deneyeceğim. /jhd –

+0

Açık Çığlık Modu = OneWay, neşe yok. CollectionChanged olayını kullanacağım ve daha iyi bir yol bulana kadar TabControl.ItemsSource'ı yeniden ayarlayacağım./jhd –

+0

ObservableCollection sınıfıyla doğru çalışan genişletilmiş sekme denetimini oluşturdum. http://vortexwolf.wordpress.com/2011/04/09/silverlight-tabcontrol-with-data-binding/ – vorrtex

cevap

0

Eğer valueconverter hata ayıklama Eğer Sence gibi sık çağrıldığını değil göreceksiniz

public ObservableCollection<TabItem> Classnames 
{ 
    get { return _classnames; } 
    set { _classnames = value; } 
} 

Açığa .

+0

Bağlanan kaynak değiştiğinde ValueConverter'ın çağrılmaması gerektiğini mi söylüyorsunuz? Bu doğru olabilir ama bana karşı mantıklıdır. ViewModel şu anda Veri projesi/ad alanında bulunduğundan, TabItem'i almak için S.W.C'ye başvurmamayı tercih ediyorum, ancak şu an sahip olduğumdan daha iyi bir çözüm. Teşekkürler./jhd –

+0

Merhaba Graeme, ValueConverter çağrılmıyor (ilk bağlandıktan sonra) çünkü ViewModel'de INotifyPropertyChanged uygulanmadı. Cevabımı aşağıya bakın. –

0

Sorun, ValueConverter öğesinin ObservableCollection<TabItem> yerine List<TabItem> döndürmesi olabilir. Bir çizgiyi değiştirip, yardımcı olup olmadığına bakın.

+0

İyi yakalama, onu değiştirerek a [bariz] etkisi yoktur. Kaynağa abone olmadı mı, davadaki Classnames? –

3

Güncelleme 19/08

özlü cevabı, görüş modeline INotifyPropertyChanged uygulamak ve Mülkiyet/Koleksiyon değiştiğinde dinleyicileri bildirmek zorunda olduğunu.

, ViewModel

* implement the interface INotifyPropertyChanged 
* define the event (public event PropertyChangedEventHandler PropertyChanged) 
* subscribe to the CollectionChanged event (Classnames.CollectionChanged += ...) 
* fire the event for listeners 

En yukarıdaki başına

/JHD


ViewModel güncellemesini INotifyPropertyChanged uygulamak ... ValueConverter şimdi Mülkiyet tüm değişiklikleri çağrısında/Koleksiyon

XAML bağlama
public class ViewModel : INotifyPropertyChanged 
{ 
    private readonly ObservableCollection<string> _classnames = new ObservableCollection<string>(); 

    public ViewModel() 
    { 
     Classnames.CollectionChanged += Classnames_CollectionChanged; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void Classnames_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     NotifyPropertyChanged("Classnames"); 
    } 

    private void NotifyPropertyChanged(string info) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      foreach (PropertyChangedEventHandler d in handler.GetInvocationList()) 
      { 
        d(this, new PropertyChangedEventArgs(info)); 
      } 
     } 
    } 

    public ObservableCollection<string> Classnames 
    { 
     get { return _classnames; } 
    } 
} 

...

<UserControl.Resources> 
    <local:ViewModel x:Key="TheViewModel"/> 
    <local:TabConverter x:Key="TabConverter" /> 
</UserControl.Resources> 

<StackPanel DataContext="{StaticResource TheViewModel}"> 
    <ListBox ItemsSource="{Binding Classnames}" /> 
    <controls:TabControl x:Name="TheTabControl" 
     ItemsSource="{Binding Classnames, Converter={StaticResource TabConverter}, ConverterParameter={StaticResource TheViewModel}}"/> 
    <Button Click="Button_Click" Content="Change Classnames" /> 
</StackPanel> 

temelde değişmeden ValueConverter (

public class TabConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      var source = value as ObservableCollection<string>; 
      if (source == null) 
       return null; 

      //also sorted out the binding syntax to pass the ViewModel as a parameter 
      var viewModel = parameter as ViewModel; 
      if (viewModel == null) 
       throw new ArgumentException("ConverterParameter must be ViewModel (e.g. ConverterParameter={StaticResource TheViewModel}"); 

      var tabItems = new List<TabItem>(); 
      foreach (string classname in source) 
      { 
       // real code dynamically loads controls by name 
       var tabItem = new TabItem 
            { 
             Header = "Tab " + classname, 
             Content = new Button {Content = "Content " + classname} 
            }; 
       tabItems.Add(tabItem); 
      } 

      return tabItems; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
+0

not: PropertyChanged olayını gerçek kodda her CollectionChanged olayına göndermek istemezsiniz ... kaynak koleksiyonunu manipüle ettikten sonra bir PropertyChanged olayını yükseltmelisiniz./JHD –

3

Ben bunun bu noktada biraz eski sorudur farkındayım ama herkesin neden ihtiyaç açıkladı ettiğini bilmiyorum INOTifyPropertyChanged görünümünüzdeki bağlı özelliğin üzerinde yapmak için

ItemsControl'un kendisi olması gerekir. ItemsControl'ün yeniden değerlendirmesine neden olması için koleksiyon değişikliği olayları için bir ObservableCollection'a bağlı. Dönüştürücünüz, tek bir GözlemlenebilirKoleksiyona tutup öğeye eklemek yerine, her çağrıldığında ayrı bir Liste (veya Gözlenebilir) koleksiyonuna dönüyor. Bu nedenle, bu koleksiyonlar hiçbir zaman koleksiyonda hiçbir değişiklik yapılmadı ve üzerlerinde ortaya çıkan olaylar değişmedi ... her zaman yeni, her bağlanma yeniden yapıldığı zaman.

Yükseltme PropertyChanged, yeniden değerlendirilmek üzere bağlayıcınızı zorlar ve dönüştürücünüzü yeniden çalıştırır, farklı bir koleksiyona dönüşür ve değişikliklerinizi yansıtır.

Dönüştürmeyi, bir Dönüştürücü yerine ViewModel'inizde yapmak daha iyi bir yaklaşım olabilir. Doğrudan bağladığınız ve değiştirdiğiniz TabItem'in GözlemlenebilirKoleksiyonunu ortaya çıkarın. TabControl, daha sonra PropertyChanged'ı yükseltmek ve tüm bağları yeniden değerlendirmek gerekmeden doğrudan koleksiyonunuza yapılan değişiklikleri görmelidir.

[Düzenleme - Eklendi yaklaşımım] ViewModel: public class TabSampleViewModel { özel ObservableCollection _tabItems = new ObservableCollection();

public TabSampleViewModel() 
    { 
     AddTabItem("Alpba"); 
     AddTabItem("Beta"); 
    } 

    public ObservableCollection<TabItem> TabItems 
    { 
     get 
     { 
      return _tabItems; 
     } 
    } 

    public void AddTabItem(string newTabItemName) 
    { 
     TabItem newTabItem = new TabItem(); 

     newTabItem.Header = newTabItemName; 
     newTabItem.Content = newTabItemName; 

     TabItems.Add(newTabItem); 
    } 
} 

Görünüm: < kontrolleri: TabControl ItemsSource = "{TabItems Bağlama}" varsayılan mod OneTime/>