2010-06-29 4 views
4

J'ai un ListBox dont ItemsSource est lié à une liste d'objets. La zone de liste a un ItemTemplate avec un DataTemplate contenant un TextBlock. Le texte du bloc de texte est lié à la propriété Nom de l'objet (c'est-à-dire Texte = "{Nom de liaison}").Dans WPF, comment modifier la liaison de texte Textblock d'un DataTemplate dans le code?

Je voudrais fournir un bouton radio pour montrer différentes vues de la même liste. Par exemple, permettez à un utilisateur de basculer entre la propriété Name et une propriété ID.

J'ai trouvé une réponse SO pour cela à 2381740 mais j'ai aussi border et un style de textbox défini dans le modèle de données (voir le code ci-dessous).

Y a-t-il un moyen de réinitialiser la liaison Textblock? Je ne veux pas avoir à recréer l'ensemble du datatemplate. En fait, je ne suis même pas sûr de savoir comment faire cela, y at-il un moyen facile de traduire xaml en code ?.

Merci Cody

<DataTemplate> 
    <Border Margin="0 0 2 2" 
      BorderBrush="Black" 
      BorderThickness="3" 
      CornerRadius="4" 
      Padding="3"> 
     <TextBlock Style="{StaticResource listBoxItemStyle}" 
       Text="{Binding Name}" /> 
    </Border> 
</DataTemplate> 

Répondre

7

Juste faire simple pour vous et utiliser deux TextBlocks et cache l'un d'entre eux.

XAML:

<Window x:Class="Test.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="300" Width="300"> 

    <Window.Resources> 
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> 
    </Window.Resources> 

    <StackPanel> 
    <RadioButton Name="nameRadioBtn" Content="Name" IsChecked="True"/> 
    <RadioButton Name="lengthRadioBtn" Content="Length" /> 
    <ListBox 
     ItemsSource="{Binding Path=Items}"> 
     <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Border BorderBrush="Red" BorderThickness="1"> 
      <Grid> 
       <TextBlock 
       Text="{Binding .}" 
       Visibility="{Binding Path=IsChecked, ElementName=nameRadioBtn, 
        Converter={StaticResource BooleanToVisibilityConverter}}" /> 
       <TextBlock 
       Text="{Binding Path=Length}" 
       Visibility="{Binding Path=IsChecked, ElementName=lengthRadioBtn, 
        Converter={StaticResource BooleanToVisibilityConverter}}" /> 
      </Grid> 
      </Border> 
     </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
    </StackPanel>   
</Window> 
code

derrière:

using System.Collections.Generic; 
using System.Windows; 

namespace Test 
{ 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 

      DataContext = this; 
     } 

     public IEnumerable<string> Items 
     { 
      get 
      { 
       return new List<string>() {"Bob", "Sally", "Anna"}; 
      } 
     } 
    } 
} 
+0

Ceci est une bien meilleure solution, d'autant plus qu'il supporte les deux. Merci! – code

+1

Oui, c'est une très bonne solution étant donné l'exigence de lier deux valeurs aux boutons radio. (+1) Vous pouvez également être intéressé par la solution plus générale que j'ai ajoutée. –

2

Vous pouvez également utiliser un convertisseur de valeur pour choisir une propriété de votre objet de données. Vous devrez vous lier à l'ensemble de l'objet au lieu des propriétés individuelles. Si votre objet de données implémente INotifyPropertyChanged, cette solution ne fonctionnera pas pour vous.

XAML

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

    <Window.Resources> 
     <Test:PropertyPickerConverter x:Key="PropertyPickerConverter" /> 
    </Window.Resources> 

    <StackPanel> 
     <RadioButton Content="Name" Click="OnRadioButtonClick" IsChecked="True"/> 
     <RadioButton Content="Length" Click="OnRadioButtonClick" /> 
     <ListBox 
      ItemsSource="{Binding Path=Items}" 
      Name="_listBox"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <Border BorderBrush="Red" BorderThickness="1"> 
         <StackPanel> 
          <TextBlock 
           Text="{Binding ., Converter={StaticResource PropertyPickerConverter}}" /> 
         </StackPanel> 
        </Border> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
    </StackPanel> 

</Window> 
Code

derrière:

using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 

namespace Test 
{ 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 

      _propertyPickerConverter = FindResource("PropertyPickerConverter") as PropertyPickerConverter; 
      _propertyPickerConverter.PropertyName = "Name"; 

      DataContext = this; 
     } 

     public IEnumerable<string> Items 
     { 
      get 
      { 
       return new List<string>() {"Bob", "Sally", "Anna"}; 
      } 
     } 

     private void OnRadioButtonClick(object sender, RoutedEventArgs e) 
     { 
      _propertyPickerConverter.PropertyName = (sender as RadioButton).Content as string; 

      _listBox.Items.Refresh(); 
     } 

     private PropertyPickerConverter _propertyPickerConverter; 
    } 

    public class PropertyPickerConverter : IValueConverter 
    { 
     public string PropertyName { get; set; } 

     #region IValueConverter Members 
     public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      string item = value as string; 
      switch (PropertyName) 
      { 
       case "Name": return item; 
       case "Length": return item.Length; 
       default: return null; 
      } 
     } 

     public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new System.NotImplementedException(); 
     } 
     #endregion 
    } 
} 
13

solution de Wallstreet programmeur fonctionne bien pour vous parce que vous utilisez les boutons radio. Cependant, il y a une solution plus générale que je pensais devoir mentionner aux futurs lecteurs de cette question.

Vous pouvez modifier votre DataTemplate utiliser simplement « {} Reliure »

<DataTemplate x:Key="ItemDisplayTemplate"> 
    <Border ...> 
    <TextBlock ... 
       Text="{Binding}" /> 
    </Border> 
</DataTemplate> 

Ensuite, dans le code que vous n'avez pas à recréer un DataTemplate complet. Tout ce que vous avez à faire est de recréer ceci:

<DataTemplate> 
    <ContentPresenter Content="{Binding Name}" ContentTemplate="{StaticResource ItemDisplayTemplate}" /> 
</DataTemplate> 

qui est facile:

private DataTemplate GeneratePropertyBoundTemplate(string property, string templateKey) 
{ 
    var template = FindResource(templateKey); 
    FrameworkElementFactory factory = new FrameworkElementFactory(typeof(ContentPresenter)); 
    factory.SetValue(ContentPresenter.ContentTemplateProperty, template); 
    factory.SetBinding(ContentPresenter.ContentProperty, new Binding(property)); 
    return new DataTemplate { VisualTree = factory }; 
} 

Cela est particulièrement pratique si vous avez de nombreuses propriétés, même dans votre exemple de bouton radio.

Questions connexes