【问题标题】:How to make the textblock text centered in a button with image and text if no image is available in WPF如果 WPF 中没有可用的图像,如何使文本块文本在带有图像和文本的按钮中居中
【发布时间】:2016-11-15 12:53:18
【问题描述】:

我有一个带有图像和文本块的按钮。 按钮是根据数据库中的值动态创建的。 现在对于一个特定的值,文本存在并且没有图像,我想在按钮的中心(水平和垂直)显示该文本,但它不起作用。

请在下面找到 xaml:

<ItemsControl ItemsSource="{Binding CategoriesList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Width="100" Margin="5" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
                <Button.Template>
                    <ControlTemplate>
                        <Border CornerRadius="10" Background="Maroon">
                            <StackPanel Orientation="Vertical">
                                <Image Source="{Binding CategoryImagePath}" Height="50"></Image>
                                <TextBlock Text="{Binding CategoryName}" Height="20" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

如果没有可用的图像,我只想在按钮上显示文本,但它应该居中。

如果有图像,那么我会同时显示图像和文本,但是当图像不可用时,会显示文本但它不在中心它移动到按钮的顶部。

【问题讨论】:

    标签: xaml imagebutton


    【解决方案1】:

    您可以使用DataTemplateSelector 来选择不同的模板,具体取决于您是否有图像。这样的选择器可能如下所示:

    public sealed class ButtonTemplateSelector : DataTemplateSelector
    {
        /// <summary>
        /// Gets or sets the <see cref="DataTemplate"/> to use when we have an image.
        /// The value is set in XAML.
        /// </summary>
        public DataTemplate ImageTemplate { get; set; }
    
        /// <summary>
        /// Gets or sets the <see cref="DataTemplate"/> to use when we don't have an image.
        /// The value is set in XAML.
        /// </summary>
        public DataTemplate NoImageTemplate { get; set; }
    
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            Category category = item as Category;
            if (category != null)
            {
                return category.CategoryImagePath == null ? NoImageTemplate : ImageTemplate;
            }
    
            return base.SelectTemplate(item, container);
        }
    }
    

    我假设一个模型对象是这样的:

    public class Category
    {
        public string CategoryImagePath { get; set; }
    
        public string CategoryName { get; set; }
    }
    

    在 XAML 中创建并初始化 ButtonTemplateSelector 资源,然后从 ItemsControl 引用它:

    <Window
        x:Class="WPF.MainWindow"
        x:Name="self"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:wpf="clr-namespace:WPF"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="350"
        Width="525">
        <Grid>
            <Grid.Resources>
                <wpf:ButtonTemplateSelector x:Key="ButtonTemplateSelector">
                    <wpf:ButtonTemplateSelector.ImageTemplate>
                        <DataTemplate DataType="wpf:Category">
                            <Button
                                Width="100"
                                Margin="5"
                                HorizontalContentAlignment="Center"
                                VerticalContentAlignment="Center">
                                <Button.Template>
                                    <ControlTemplate>
                                        <Border CornerRadius="10" Background="Maroon">
                                            <StackPanel Orientation="Vertical">
                                                <Image
                                                    Source="{Binding CategoryImagePath}"
                                                    Height="50" />
                                                <TextBlock
                                                    Foreground="White"
                                                    Text="{Binding CategoryName}"
                                                    Height="20"
                                                    HorizontalAlignment="Center"
                                                    VerticalAlignment="Center" />
                                            </StackPanel>
                                        </Border>
                                    </ControlTemplate>
                                </Button.Template>
                            </Button>
                        </DataTemplate>
                    </wpf:ButtonTemplateSelector.ImageTemplate>
                    <wpf:ButtonTemplateSelector.NoImageTemplate>
                        <DataTemplate DataType="wpf:Category">
                            <Button
                                Width="100"
                                Margin="5"
                                HorizontalContentAlignment="Center"
                                VerticalContentAlignment="Center">
                                <Button.Template>
                                    <ControlTemplate>
                                        <Border
                                            CornerRadius="10"
                                            Background="Maroon"
                                            Height="70">
                                            <TextBlock
                                                Foreground="White"
                                                Text="{Binding CategoryName}"
                                                Height="20"
                                                HorizontalAlignment="Center"
                                                VerticalAlignment="Center" />
                                        </Border>
                                    </ControlTemplate>
                                </Button.Template>
                            </Button>
                        </DataTemplate>
                    </wpf:ButtonTemplateSelector.NoImageTemplate>
                </wpf:ButtonTemplateSelector>
            </Grid.Resources>
            <ItemsControl
                DataContext="{Binding ElementName=self}"
                ItemsSource="{Binding CategoriesList}"
                ItemTemplateSelector="{StaticResource ButtonTemplateSelector}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Grid>
    </Window>
    

    为了完整起见,窗口的代码隐藏:

    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        public IEnumerable<Category> CategoriesList { get; } = new List<Category>
            {
                new Category { CategoryName = "First", CategoryImagePath = "/Assets/Square.bmp" },
                new Category { CategoryName = "Second", CategoryImagePath = null },
            };
    }
    

    这显示如下,我认为这就是您要问的:

    【讨论】:

    • 还有其他选项——例如,您对图像高度进行了硬编码。如果您改为硬编码按钮高度,则图像部分可能会坍塌成虚无,并且您会留下一个垂直居中的字符串。不过,这取决于您的数据...
    • 感谢彼得的回答。你明白我想要什么,但如果你能帮助我,我没有几个问题。
    • 当然,我会试一试。 (如果您喜欢这个答案,请考虑接受。)
    • 我是否需要为 ItemsControl 设置数据上下文,即使我正在为我们拥有此项目控件标记的用户控件设置数据上下文。 2)在进行所需的更改后,文本也没有居中。有什么方法可以调试 xaml,因为我调试时模板选择器代码按预期工作。
    • 您不必显式设置ItemsControlDataContext;如果是null,它只会沿着层次结构向上走。我只需要设置它somewher 即可获得运行示例——将它设置在GridWindow 上也可以。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 2019-06-13
    • 2012-07-06
    相关资源
    最近更新 更多