1

我正在尝试制作一个按钮,该按钮的样式可以根据可用空间的多少来更改其布局以使其自身更小。

这些按钮将始终有一个堆栈面板,其中包含一个图像和一个文本块。我的目标是能够为这些按钮定义 3-4 种不同的样式,每种样式都会产生不同的按钮大小。

对于每个按钮图像,如果图像具有不同的分辨率,我有 4 个版本。16、32、48和64。这些图像存储在不同的文件夹中;即Images\Icons\16\Add.png 和Images\Icons\32\Add.png。这两张图是一样的,只是大小不同。我选择使用多种尺寸,因为我发现只有一张图像并缩放其尺寸会导致它相当模糊。

为了方便选择不同大小的图像,我创建了一个转换器,我在绑定图像源时使用它:

class ImagePathResolutionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Image sender = (Image)value;
        int imageSize = (parameter != null) ? (parameter is int) ? (int)parameter : (parameter is string) ? Int32.Parse((string)parameter) : 16 : 16;
        Uri returnImage = new Uri(String.Format(@"Images\Icons\{0}\{1}", imageSize, sender.Tag as string), UriKind.Relative);
        return returnImage;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

}

绑定看起来像这样:

<Setter Property="Source" 
        Value="{Binding ., 
                Converter={StaticResource ImagePathResolutionConverter}, 
                RelativeSource={RelativeSource Self}, 
                ConverterParameter='16'}" 
/>

使用此设置意味着我可以将 16、32、48 或 64 传递给 ConverterParameter,并且将返回适当的图像路径。

现在,对于这个例子,我有两种风格;

大的:

<!-- Big Button Container Style -->
<Style TargetType="Button" x:Key="MultiResButton_Big">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Top" />
    <Style.Resources>
        <!-- Button.StackPanel Style -->
        <Style TargetType="StackPanel">
            <Setter Property="Orientation" Value="Vertical" />
            <Style.Resources>
                <!-- Button.StackPanel.Image Style -->
                <Style TargetType="Image">
                    <Setter Property="Stretch" Value="None" />
                    <Setter Property="Margin" Value="5 2 5 0" />
                    <Setter Property="Source" Value="{Binding ., Converter={StaticResource ImagePathResolutionConverter}, RelativeSource={RelativeSource Self}, ConverterParameter='32'}" />
                </Style>
                <!-- Button.StackPanel.TextBlock Style -->
                <Style TargetType="TextBlock">
                    <Setter Property="Margin" Value="5 0 5 2" />
                </Style>
            </Style.Resources>
        </Style>
    </Style.Resources>
</Style>

...和小

<!-- Small Button Container Style -->
<Style TargetType="Button" x:Key="MultiResButton_Small">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Top" />
    <Style.Resources>
        <!-- Button.StackPanel Style -->
        <Style TargetType="StackPanel">
            <Setter Property="Orientation" Value="Horizontal" />
            <Style.Resources>
                <!-- Button.StackPanel.Image Style -->
                <Style TargetType="Image">
                    <Setter Property="Stretch" Value="None" />
                    <Setter Property="Margin" Value="5 2" />
                    <Setter Property="Source" Value="{Binding ., Converter={StaticResource ImagePathResolutionConverter}, RelativeSource={RelativeSource Self}, ConverterParameter='16'}" />
                </Style>
                <!-- Button.StackPanel.TextBlock Style -->
                <Style TargetType="TextBlock">
                    <Setter Property="Margin" Value="0 5 2 5" />
                </Style>
            </Style.Resources>
        </Style>
    </Style.Resources>
</Style>    

这些按钮之一的 XAML 是:

<Button Style="{StaticResource ResourceKey=MultiResButton_Big}">
    <StackPanel>
        <Image Tag="Multi.png" />
        <TextBlock Text="Button Text" />
    </StackPanel>            
</Button>

目前,我可以为其中一个或这些设置一个按钮,结果是一个大按钮或小按钮。现在我只需要弄清楚如何确定何时使用哪个,以及如何以编程方式使用。

在我看来,我有两个选择:将两种样式合并为一个并使用某种触发器,或者创建一个 styleSelector 类并让它选择要使用的样式。

我的问题是我不知道如何以编程方式确定要使用的样式。我发现当按钮被推到容器的可见范围之外时,“RenderSize.Width”设置为 0。我的问题是,当 5 个按钮在容器的可见边界之外时,将 5 设置为使用较小的样式将无济于事......我还必须为其他可见按钮使用较小的尺寸才能“制作”超出界限的 5 个房间。

我很乐意为容器中的所有按钮设置样式...当一个按钮 renderSize.Width = 0 时,将所有同级按钮降低到样式大小较低...

我正在尝试的甚至可能吗?我是否必须创建一个自定义容器才能覆盖所有子控件的呈现?如果可以的话,我宁愿避免这种情况......但我看不到任何其他可能的方式......

作为我正在尝试完成的示例,打开 Word 或 Excel 2007/2010,然后慢慢调整窗口大小以使其更小。当你这样做时,ribon 中的按钮会“收缩”以腾出更多空间。

对于我是否从正确的方向接近这个问题,我将不胜感激。

4

1 回答 1

0

您可以使用第二个转换器来绑定样式。

创建一个 IMultiValueConverter,它采用两个值,ActualWidth 和计算将基于的元素(在我的示例中,我使用的是 Window):

class ImageButtonStyleSelectorConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        Double actualWidth = values[0] as Double? ?? 0;
        FrameworkElement element = values[1] as FrameworkElement;

        if (element != null)
        {
            // perform calculations and return button size (using even/odd for illustration purposes)
            if (element.Width % 2 == 0)
            {
                return element.Resources["MultiResButton_Small"];
            }
            else
            {
                return element.Resources["MultiResButton_Big"];
            }
        }
        return Binding.DoNothing;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

然后,更改您的按钮以使用转换器选择样式:

        <Button>
            <Button.Style>
                <MultiBinding Converter="{StaticResource ImageButtonStyleSelectorConverter}"
                              FallbackValue="{StaticResource MultiResButton_Big}">
                    <Binding RelativeSource="{RelativeSource AncestorType=Window, Mode=FindAncestor}" Path="ActualWidth"/>
                    <Binding RelativeSource="{RelativeSource AncestorType=Window, Mode=FindAncestor}" Path="."/>
                </MultiBinding>
            </Button.Style>
            <StackPanel>
                <Image Tag="Multi.png" />
                <TextBlock Text="Button Text" />
            </StackPanel>
        </Button>

我添加了 FallbackValue,否则我无法从设计视图中看到任何一种样式。

于 2012-04-13T18:04:49.413 回答