【问题标题】:WPF Button with image + text and change the image in codebehind带有图像+文本的WPF按钮并在代码隐藏中更改图像
【发布时间】:2013-08-07 07:36:40
【问题描述】:

我正在尝试创建一个包含图像和文本的按钮。但是,图像可以在运行时通过后面的代码进行更改。我的图片是 png,每个人都在我的 ResourceDictionary 中:

<BitmapImage x:Key="iconLogIn" UriSource="/Images/Icons/lock.png" />

所以,我从这种风格开始,没有模板或 ContentTemplate。

<Style x:Key="MyTestButton" TargetType="{x:Type Button}">
    <Setter Property="Height" Value="80" />
    <Setter Property="Width" Value="100" />
</Style>

我的 XAML 是:

<Button x:Name="cmdOption1" Style="{StaticResource MyTestButton}" Margin="8" Click="cmdOption1_Click">
    <Image Source="{DynamicResource iconLogIn}" />
</Button>

然后,我更改图像的代码是:

cmdOption1.Content = new Image() { Source = ((BitmapImage)FindResource("iconLogOut")) };

到目前为止,这是可行的。

但是,只有图片,我想在图片下面放一个文字。

所以我已经阅读了this 的帖子,HighCore 的答案,选项 #2,可能会满足我的要求。但是,现在出现了一个新问题:

首先,这是新样式,带有一个简单的模板

<Style x:Key="MyTestButton" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="#EEEEEE" />
    <Setter Property="Foreground" Value="DarkSlateGray" />
    <Setter Property="Height" Value="80" />
    <Setter Property="Width" Value="100" />
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="2"/>
    <Setter Property="FontSize" Value="12" />
    <Setter Property="FontWeight" Value="SemiBold" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="BorderBrush" Value="DarkGray" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border>
                    <StackPanel>
                        <Image Source="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}" Height="50" Width="50"/>
                        <ContentPresenter Grid.Row="0" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" />
                    </StackPanel>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Foreground" Value="DarkOrange" />
                        <Setter Property="OpacityMask" Value="#AA888888"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="Gray" />
                        <Setter Property="BorderBrush" Value="DarkGray" />
                        <Setter Property="Background" Value="White" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
</Style>

我的新 XAML 是:

<Button x:Name="cmdOption1" Tag="{StaticResource iconLogIn}" Content="LOG IN" Style="{StaticResource MyTestButton}" Margin="8" Click="cmdOption1_Click" />

*也带有 Tag="{DynamicResource iconLogIn}"

还有我后面的代码来改变图片和文字:

cmdOption1.Tag = new Image() { Source = ((BitmapImage)FindResource("iconLogOut")) };
cmdOption1.Content = "LOG OUT";

这样,内容文本从“LOG IN”变为“LOG OUT”。但是图像不再显示,只是在图像的位置没有任何内容,并且没有抛出错误或异常。

我想知道解决方案是什么,发生了什么?为什么图像只是没有改变,而是消失了?

提前致谢。

【问题讨论】:

    标签: wpf image xaml button


    【解决方案1】:

    我认为您应该考虑一种更简洁的方法,即使用 MVVM、数据绑定和 INotifyPropertyChanged 的​​实现。

    首先:使用 ViewModel,在其中定义定义 ImageUri 和 Text 的属性:

        private Uri _myImageUriProperty;
        public Uri MyImageUriProperty
        {
            get { return _myImageUriProperty; }
            set { _myImageUriProperty = value; RaisePropertyChanged(() => MyImageUriProperty); }
        }
    
        private string _myTextBlockProperty;
        public string MyTextBlockProperty
        {
            get { return _myTextBlockProperty; }
            set { _myTextBlockProperty = value; RaisePropertyChanged(() => MyTextBlockProperty); }
        }
    

    此外:在您的按钮中,您可以使用占位符在按钮中放置多个 UI 元素。并将它们从您的视图模型绑定到您的属性:

        <Button x:Name="MyButton"
                Click="MyButton_OnClick">
            <StackPanel>
                <Image x:Name="MyImage"
                       Source="{Binding MyImageUriProperty}" />
                <TextBlock x:Name="MyTextBlock"
                           Text="{Binding MyTextBlockProperty}" />
            </StackPanel>
        </Button>
    

    最后:使用代码隐藏中的点击事件来重置视图模型中的值(您已在代码隐藏的构造函数中将其设置为 DataContext。PropertyChanged 事件将触发 UI 中的更新。

        private void MyButton_OnClick(object sender, RoutedEventArgs e)
        {
            ViewModel.MyImageUriProperty = new Uri("mynewuri.png", UriKind.Relative)
            ViewModel.MyTextBlockProperty = "LogOut";
        }
    

    【讨论】:

    • 我喜欢您的回答,由于时间限制,我无法更改为 MVVM。 +1。
    【解决方案2】:

    您创建一个新的 Image 控件并将其分配给 Button 的 Tag 属性。因此,ControlTemplate 中的 Image 控件将其 Source 属性设置为另一个 Image 控件。那是行不通的。只需将资源中的 BitmapImage 分配给Tag

    而不是

    cmdOption1.Tag = new Image() { Source = ((BitmapImage)FindResource("iconLogOut")) };
    

    你应该简单地写这个:

    cmdOption1.Tag = (BitmapImage)FindResource("iconLogOut");
    

    【讨论】:

      【解决方案3】:

      您的 XAML 工作正常。代码中唯一需要以这种方式设置Image

      private void cmdOption1_Click(object sender, RoutedEventArgs e)
      {
          BitmapImage MyBitmapImage = ((BitmapImage)FindResource("iconLogOut"));
          cmdOption1.Tag = MyBitmapImage;
      
          cmdOption1.Content = "LOG OUT";
      }
      

      作为替代方法(仅用于比较方法),您可以通过函数FindChild&lt;&gt; 使用此技巧而不使用Tag。你的模板部分:

      <ControlTemplate TargetType="{x:Type Button}">
          <Border>
              <StackPanel>
                  <Image x:Name="MyContentImage" Source="{StaticResource iconLogIn}" Height="50" Width="50" />
                  <ContentPresenter Grid.Row="0" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" />
              </StackPanel>
          </Border>
      
          ...
      

      后面的代码:

      private void cmdOption1_Click(object sender, RoutedEventArgs e)
      {
          // Find the Image in template
          Image MyContentImage = FindChild<Image>(cmdOption1, "MyContentImage");
          MyContentImage.Source = ((BitmapImage)FindResource("iconLogOut")); 
      
          cmdOption1.Content = "LOG OUT";
      }
      

      FindChild&lt;&gt;列表:

          public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
          {
              if (parent == null)
              {
                  return null;
              }
      
              T foundChild = null;
      
              int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
      
              for (int i = 0; i < childrenCount; i++)
              {
                  var child = VisualTreeHelper.GetChild(parent, i);
                  T childType = child as T;
      
                  if (childType == null)
                  {
                      foundChild = FindChild<T>(child, childName);
      
                      if (foundChild != null) break;
                  }
                  else
                      if (!string.IsNullOrEmpty(childName))
                      {
                          var frameworkElement = child as FrameworkElement;
      
                          if (frameworkElement != null && frameworkElement.Name == childName)
                          {
                              foundChild = (T)child;
                              break;
                          }
                          else
                          {
                              foundChild = FindChild<T>(child, childName);
      
                              if (foundChild != null)
                              {
                                  break;
                              }
                          }
                      }
                      else
                      {
                          foundChild = (T)child;
                          break;
                      }
              }
      
              return foundChild;
          }   
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-20
        • 1970-01-01
        • 1970-01-01
        • 2011-02-11
        • 2013-11-28
        • 1970-01-01
        相关资源
        最近更新 更多