2010-01-26 9 views
2

J'ai créé une coutume ComboBox comme suit: (note, le code est incorrect, mais vous devriez obtenir l'idée générale.) Le ComboBox contient 2 propriétés de dépendance qui comptent: TitleText et DescriptionText.Reliure à l'élément sélectionné dans un ItemsControl

<Grid> 
    <TextBlock x:Name="Title"/> 
    <Grid x:Name="CBG"> 
    <ToggleButton/> 
    <ContentPresenter/> 
    <Popup/> 
    </Grid> 
</Grid> 

Je veux utiliser ce ComboBox pour afficher un large éventail d'options. J'ai créé une classe appelée réglage qui hérite de DependencyObject pour créer des objets utilisables, j'ai créé un DataTemplate pour lier le contenu de cet objet Settings à mon ComboBox et créé un UserControl qui contient un ItemsControl qui a comme modèle mon mentionné précédemment DataTemplate. Je peux le remplir avec Setting objets.

<DataTemplate x:Key="myDataTemplate"> 
    <ComboBox TitleText="{Binding Title}" DescriptionText="{Binding DescriptionText}"/> 
</DataTemplate> 

<UserControl> 
    <Grid> 
    <StackPanel Grid.Column="0"> 
     <ItemsControl Template="{StaticResource myDataTemplate}"> 
     <Item> 
      <Setting Title="Foo" Description="Bar"> 
      <Option>Yes</Option><Option>No</Option> 
      </Setting> 
     </Item> 
     </ItemsControl> 
    </StackPanel> 
    <StackPanel Grid.Column="1"> 
     <TextBlock x:Name="Description"/> 
    </StackPanel> 
    </Grid> 
</UserControl> 

Je voudrais avoir le DescriptionText du sélectionné ComboBox (sélectionné soit par le IsFocus du contrôle ComboBox ou la propriété IsOpen du pop-up) à placer dans le DescriptionTextBlock dans mon UserControl.

J'ai réussi à remplacer mon ItemsControl par un ListBox mais cela a causé plusieurs problèmes: il affichait toujours une barre de défilement même si je l'avais désactivé, il ne captait pas le focus lorsque mon popup était ouvert mais seulement quand je explicitement sélectionné l'élément dans mon ListBox, quand j'ENABLED la propriété OverridesDefaultStyle le contenu du ListBox ne se présentent pas du tout, je devais re-thème le contrôle ListBox pour correspondre à ma disposition UserControl ...

Quelle est la le meilleur et le plus facile moyen d'obtenir mon DescriptionText se présenter sans utiliser un ListBox ou en créant un Selector personnalisé contrôle (car cela a eu le même effet qu'un ListBox)?

Le but à la fin est de boucle à travers tous les éléments (les obtenir peut-être dans un ObservableCollection ou une sorte et de les enregistrer dans mon fichier de paramètres.

+0

Il n'est pas complètement clair à moi ce que vous essayez ici. Avez-vous un code-behind, ou utilisez-vous simplement Binding? – codekaizen

+0

J'ai un code derrière le fichier, mais pour le moment il n'est pas vraiment utilisé. Chaque ComboBox contient une petite description sur l'option qu'il modifie, lorsque vous sélectionnez l'élément ComboBox (se concentre ou le popup est ouvert) l'idée est de mettre à jour le TextBlock Description sur la droite avec la description appropriée. – Jensen

Répondre

1

Je pense que je sais ce que vous essayons de faire, voici une solution possible:

Vous devez utiliser un contrôle ListBox (ou tout ce qui dérive du contrôle Selector) pour utiliser la propriété SelectedItem.

<UserControl> 
    <Grid> 
    <StackPanel Grid.Column="0"> 
     <ListBox x:Name="SettingListBox" Template="{StaticResource myDataTemplate}"> 
     <Item> 
      <Setting Title="Foo" Description="Bar"> 
      <Option>Yes</Option><Option>No</Option> 
      </Setting> 
     </Item> 
     </ListBox > 
    </StackPanel> 
    <StackPanel Grid.Column="1"> 
     <TextBlock x:Name="Description" 
      Text="{Binding SelectedItem.Description, ElementName=SettingListBox}"/> 
    </StackPanel> 
    </Grid> 
</UserControl> 

Pour résoudre le problème où votre ListBox ne se concentre pas sur l'élément lorsque vous ouvrez le menu déroulant ComboBox, j'ai une propriété attachée qui résoudra pour vous.

public class ListBoxHelper 
{ 
    #region Dependency Property 

    public static bool GetCanFocusParent(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(CanFocusParentProperty); 
    } 

    public static void SetCanFocusParent(DependencyObject obj, bool value) 
    { 
     obj.SetValue(CanFocusParentProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for CanFocusParent. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty CanFocusParentProperty = 
     DependencyProperty.RegisterAttached("CanFocusParent", typeof(bool), typeof(ListBoxHelper), new UIPropertyMetadata(false, OnCanFocusParentChanged)); 



    #endregion 

    private static void OnCanFocusParentChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 
    { 
     var element = obj as UIElement; 
     if(element == null) return; 

     if((bool)args.NewValue) 
      element.PreviewMouseDown += FocusOnParent; 
     else 
      element.PreviewMouseDown -= FocusOnParent; 
    } 

    private static void FocusOnParent(object sender, RoutedEventArgs e) 
    { 
     var listBoxItem = VisualUpwardSearch<ListBoxItem>(sender as DependencyObject) as ListBoxItem; 
     if (listBoxItem != null) listBoxItem.IsSelected = true; 
    } 

    public static DependencyObject VisualUpwardSearch<T>(DependencyObject source) 
    { 
     while (source != null && source.GetType() != typeof(T)) 
      source = VisualTreeHelper.GetParent(source); 

     return source; 
    } 
} 

Qu'est-ce que cette petite classe n'est d'aider votre contrôle de se concentrer sur la zone de liste élément sélectionné lorsque vous activez un contrôle à l'intérieur (ie. Votre ComboBox). Cela fonctionne lorsque la souris est cliquée dans l'élément ListBox.

Maintenant, tout ce que vous avez à faire est de le joindre à votre ComboBox comme ceci:

<DataTemplate x:Key="myDataTemplate"> 
    <ComboBox 
     TitleText="{Binding Title}" 
     DescriptionText="{Binding DescriptionText}" 
     CotrolHelper:ListBoxHelper.CanFocusParent="true"/> 
</DataTemplate> 

Où ControlHelper est:

xmlns:ControlHelper="clr-namespace:WhereYouPutYour.ListBoxHelperClass" 

Et enfin, désactiver (mais je recommande sur Auto) la barre de défilement, vous pouvez utiliser la propriété jointe ScrollViewer dans votre ListBox comme ceci:

<ListBox 
    x:Name="SettingListBox" 
    Template="{StaticResource myDataTemplate}" 
    ScrollViewer.VerticalScrollBarVisibility="Disabled" > 
    <Item> 
     <Setting Title="Foo" Description="Bar"> 
      <Option>Yes</Option><Option>No</Option> 
     </Setting> 
    </Item> 
</ListBox > 
0

Vous pouvez utiliser un ListBox, il suffit de changer la façon dont les données est présenté. Par exemple, ce code par défaut de ne pas avoir une barre de défilement. (Je veux des barres de défilement, donc je dois envelopper explicitement la chose dans un ScrollViewer.)

   <ListBox.Template> 
        <ControlTemplate> 
         <StackPanel IsItemsHost="True" > 
         </StackPanel> 
        </ControlTemplate> 
       </ListBox.Template> 
Questions connexes