2010-06-29 56 views
4

我有一个ListBox的ItemsSource绑定到一个对象列表。 Listbox有一个带有包含TextBlock的DataTemplate的ItemTemplate。文本块的文本被绑定到对象的Name属性(即Text =“{Binding Name}”)。在WPF中如何更改代码中的DataTemplate的文本块的文本绑定?

我想提供一个单选按钮来显示同一列表的不同视图。例如,允许用户在Name属性和ID属性之间切换。

我在2381740找到了这个答案,但我也在数据模板中设置了边框和文本框样式(请参阅下面的代码)。

有没有办法重置文本块绑定?我不想重新创建整个数据模板。其实我甚至不知道如何做到这一点,是否有一种简单的方法来将xaml翻译成代码?

感谢 科迪

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

回答

7

简简单单就为自己和使用两个的TextBlocks和隐藏其中的一个。

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> 

后面的代码:

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

这是更好的解决方案,尤其是因为它支持显示两者。谢谢! – code 2010-06-29 19:53:28

+1

是的,这是一个非常好的解决方案,因为要求将两个值绑定到单选按钮。 (+1)您也可能对我添加的更一般的解决方案感兴趣。 – 2010-06-30 00:54:50

2

您还可以使用一个值转换器来接你的数据对象的任何属性。您将需要绑定到整个对象而不是单个属性。如果你的数据对象实现INotifyPropertyChanged,那么这个解决方案将不适合你。背后

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> 

代码:

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

华尔街程序员的解决方案非常适用于你,因为你使用的单选按钮。然而,我认为我应该为未来的这个问题的读者提一个更一般的解决方案。

你可以改变你的DataTemplate使用简单的“{结合}”

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

然后在代码中你不必重新建立一个完整的DataTemplate。所有你需要做的是重新创建:

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

这是很容易:

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

这是特别方便,如果你有很多的特性,甚至在你的单选按钮的例子。

相关问题