在 WPF 中,如何更改代码中 DataTemplate 的 Textblock 的文本绑定?

发布于 2024-09-07 17:29:05 字数 806 浏览 8 评论 0原文

我有一个 ListBox,其 ItemsSource 绑定到对象列表。列表框有一个 ItemTemplate 和一个包含 TextBlock 的 DataTemplate。文本块的 Text 绑定到对象的 Name 属性(即 Text="{Binding Name}")。

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

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

有没有办法重置 Textblock 绑定?我不想重新创建整个数据模板。实际上我什至不知道如何做到这一点,有没有一种简单的方法可以将 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>

I have a ListBox whose ItemsSource is bound to a list of objects. The Listbox has a ItemTemplate with a DataTemplate containing a TextBlock. The textblock's Text is bound to the object's Name property (i.e. Text="{Binding Name}").

I would like to provide a radio button to show different views of the same list. For example allow a user to toggle between the Name property and an ID property.

I found a SO answer for this at 2381740 but I also have border and a textbox style set in data template (see code below).

Is there anyway to just reset the Textblock binding? I don't want to have to recreate the entire datatemplate. Actually I'm not even sure how to do that, is there an easy way to translating xaml to code?.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

终陌 2024-09-14 17:29:05

Wallstreet Programmer 的解决方案非常适合您,因为您使用的是单选按钮。然而,我认为我应该为这个问题的未来读者提及一个更通用的解决方案。

您可以更改 DataTemplate 以使用普通的“{Binding}”,

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

如果您有很多属性,即使在单选按钮示例中,这也特别方便。

Wallstreet Programmer's solution works well for you because you are using radio buttons. However there is a more general solution that I thought I should mention for future readers of this question.

You can change your DataTemplate to use plain "{Binding}"

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

Then in code you don't have to recreate a full DataTemplate. All you have to do is recreate this:

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

which is easy:

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

This is particularly convenient if you have many properties, even in your radio button example.

﹂绝世的画 2024-09-14 17:29:05

只需让自己变得简单并使用两个文本块并隐藏其中之一即可。

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

Just make it simple for yourself and use two textblocks and hide one of them.

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

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"};
            }
        }
    }
}
九歌凝 2024-09-14 17:29:05

您还可以使用值转换器来选择数据对象的任何属性。您将需要绑定到整个对象而不是单个属性。如果您的数据对象实现了 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
    }
}

You can also use a value converter to pick any property of your data object. You will need to bind to the whole object instead of individual properties. If your data object implements INotifyPropertyChanged then this solution will not work for you.

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

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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文