【问题标题】:XAML image source set dynamically based on content基于内容动态设置的 XAML 图像源
【发布时间】:2010-06-29 12:01:38
【问题描述】:

嗯,它并不是非常动态,至少它不会在运行时改变。

我的想法是我有按钮,每个按钮都有一个独特的图像(图标 32x32)。这些按钮都共享一种我与 ControlTemplate 混淆的样式。因此,当我将鼠标悬停时,每张图像也有两种颜色,一种是正常颜色,另一种是另一种颜色。

我注意到,当我声明图像的源路径时,它们几乎都是相同的,所以我认为 DRY(不要重复自己)。如果我可以使用按钮名称或其他属性作为源路径的一部分(即图像文件的名称)会怎样。那将是很好的编程。

问题是我是 XAML、WPF 和可能一起编程的新手,所以我不知道该怎么做。我想这需要代码或某种转换器(我想我会更多地了解转换器)。这是一些代码(这不起作用,但它给了你大致的想法(希望)):

<Style x:Key="ButtonPanelBigButton" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Name="ButtonBorder"
                        Height="78"
                        MaxWidth="70"
                        MinWidth="50"
                        BorderThickness="0.5"
                        BorderBrush="Transparent"
                        CornerRadius="8" >
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="2*" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>

                        <!-- Here I wan't to put in the Name property of the button because there is a picture there to match -->
                        <Image x:Name="ButtonIcon" Source="..\Images\Icons\32x32\Blue\{Binding Name}.png" 

                               Margin="4"
                               Height="32"
                               Width="32"
                               HorizontalAlignment="Center" 
                               VerticalAlignment="Center" />

                        <TextBlock Grid.Row="1"
                                   Padding="5,2,5,2"
                                   TextWrapping="Wrap"
                                   Style="{StaticResource MenuText}"
                                   HorizontalAlignment="Center"
                                   VerticalAlignment="Center">
                            <ContentPresenter ContentSource="Content" />                
                        </TextBlock>
                    </Grid>
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True" >
                        <Setter TargetName="ButtonIcon" Property="Source" Value="..\Images\Icons\32x32\Green\user.png" /> <!-- Same Here -->
                        <Setter TargetName="ButtonBorder" Property="BorderBrush" Value="{StaticResource SecondColorBrush}" />
                        <Setter TargetName="ButtonBorder" Property="Background">
                            <Setter.Value>
                                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1" Opacity="0.5">
                                    <GradientStop Color="{StaticResource MainColor}" Offset="1" />
                                    <GradientStop Color="{StaticResource SecondColor}" Offset="0.5" />
                                    <GradientStop Color="{StaticResource MainColor}" Offset="0" />
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

希望你能明白我的意思,有人可能会帮助我,所以我的代码很好而且很干(现在我在重复自己!!!)。

【问题讨论】:

    标签: wpf xaml path


    【解决方案1】:

    你是对的:解决这个问题的简单方法是使用转换器。

    Source 属性采用 ImageSource,因此您需要自己在转换器中加载位图。

    转换器是这样使用的:

     <Image Source="{Binding Name,
                             RelativeSource={RelativeSource TemplatedParent},
                             Converter={x:Static local:ImageSourceLoader.Instance},
                             ConverterParameter=..\Images\Icons\32x32\Blue\{0}.png}" />
    

    并像这样实现:

    public class ImageSourceLoader : IValueConverter
    {
      public static ImageSourceLoader Instance = new ImageSourceLoader();
    
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {
        var path = string.Format((string)parameter, value.ToString());
        return BitmapFrame.Create(new Uri(path, UriKind.RelativeOrAbsolute));
      }
    
      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
        throw new NotImplementedException();
      }
    }
    

    请注意,这个简单的解决方案无法处理相对 Uris,因为转换器无法使用 Image 的 BaseUri 属性。如果要使用相对 Uris,可以通过绑定附加属性并使用 StringFormat 来实现:

     <Image local:ImageHelper.SourcePath="{Binding Name,
                             RelativeSource={RelativeSource TemplatedParent},
                             StringFormat=..\Images\Icons\32x32\Blue\{0}.png}" />
    

    并且附加属性的 PropertyChangedCallback 句柄在将 BaseUri 与格式化的 Uri 字符串组合后加载图像:

    public class ImageHelper : DependencyObject
    {
      public static string GetSourcePath(DependencyObject obj) { return (string)obj.GetValue(SourcePathProperty); }
      public static void SetSourcePath(DependencyObject obj, string value) { obj.SetValue(SourcePathProperty, value); }
      public static readonly DependencyProperty SourcePathProperty = DependencyProperty.RegisterAttached("SourcePath", typeof(string), typeof(ImageHelper), new PropertyMetadata
      {
        PropertyChangedCallback = (obj, e) =>
          {
            ((Image)obj).Source =
              BitmapFrame.Create(new Uri(((IUriContext)obj).BaseUri, (string)e.NewValue));
          }
      });
    }
    

    【讨论】:

    • OK 尝试让它工作,但由于路径和 {0} 导致字符串文字和标记扩展出现问题
    • OK 就像一个魅力,不得不改变一个属性,因为像这样的文字 StringFormat={}..\\Images\\Icons\\32x32\\Green\\{0}.png} "
    【解决方案2】:

    您可以使用Tag 属性并在Tag 中设置图像的完整路径,然后使用它。 下面我的代码更清楚

    *<Style TargetType="{x:Type Button}">
                <Setter Property="Background" Value="#373737" />
                <Setter Property="Foreground" Value="White" />  
               <Setter Property="FontSize" Value="12" />
                <Setter Property="SnapsToDevicePixels" Value="True" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border CornerRadius="7" Background="{TemplateBinding Background}" FlowDirection="RightToLeft">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="50"/>
                                        <ColumnDefinition Width="2"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Image x:Name="imgDistance"  Source="{Binding Tag,RelativeSource={RelativeSource TemplatedParent}}"
              
                                 Width="35" Height="35" HorizontalAlignment="Left" Margin="42,7,0,8" Grid.Column="0"/>*
    

    然后我在按钮中使用它如下

    <Button x:Name="btnDistance" Height="50" VerticalAlignment="Top" Margin="0,4,0,0" Curs
    
    or="Hand" Click="btnDistance_Click" Tag="/Images/distance.png">
    
        
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2015-03-29
      相关资源
      最近更新 更多