简体   繁体   中英

Change WPF button background image programmatically

I'm trying to create a <Button/> with a png image for the background AND a background color.

Note: The png image source may not yet be known, so I can't just put them in the template.

I've got a Style that looks like this:

<Style x:Key="MyButton" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border CornerRadius="0">
                    <Image Margin="0" Source="/MyApp;component/Images/my-image.png" Stretch="None" />
                    <Border.Style>
                        <Style TargetType="{x:Type Border}">
                            <Setter Property="Background" Value="LimeGreen" />
                        </Style>
                    </Border.Style>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

which gives me a button with a png image on top of a solid LimeGreen background.

My MainWindow.xaml looks somewhat like this:

<Button Style="{StaticResource MyButton}" Click="btnMine_Click" /* some other props */ />

and the code behind it is like this:

private void btnMine_Click(object sender, RoutedEventArgs e)
{
    // TODO: change the image src on this button
    var myButton = sender as Button;

    // This won't work:
    // myButton.Border.Image.Source = getNewImageString();
}

How do I change the image source from /MyApp2;component/Images/my-image.png to something else?

Sigh, in Windows Forms it was literally one line. In WPF it looks like it will be several hundred.

That's because it was the ONLY thing you could place in a button in winforms. WPF is a true UI framework, not some random semi-deprecated dinosaur that only allows to do the default stuff (which by the way looks horrible).

Option 1: Place the Image as Button's Content :

If you just want to place an Image in the button, and nothing else, why not just do that?

        <Style TargetType="Button">
            <Setter Property="Background" Value="LimeGreen"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border Background="{TemplateBinding Background}">
                            <ContentPresenter ContentSource="Content"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Then:

     <Button>
        <!-- Background not set, defaults to what's set in the Style -->
        <Image Source="./ChessPieces/BlackKnight.png"/>
    </Button>
    <Button Background="Red">
        <Image Source="./ChessPieces/BlackBishop.png"/>
    </Button>
    <Button Background="Blue">
        <Image Source="./ChessPieces/BlackPawn.png"/>
    </Button>

    <!-- WPF's idea of "Dynamic" is not the same as win(hack)forms' -->
    <Button Background="White">
        <Image Source="{Binding SomeStringPropertyDefinedInAViewModel}"/>
    </Button>

Result:

在此处输入图片说明

Option 2 (not very elegant): Use the Tag Property:

If, in addition to the Image, you want to put something else inside the Button, you can resort to a somewhat hacky approach of putting the ImageSource in the Button's Tag property.

        <Style TargetType="Button">
            <Setter Property="Background" Value="LimeGreen"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border Background="{TemplateBinding Background}">
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"
                                       Height="50" Width="50"/>
                                <ContentPresenter ContentSource="Content"/>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Then:

    <Button Tag="./ChessPieces/BlackKnight.png"
            Background="Blue"
            Foreground="White"
            Content="Some Text"/>

    <Button Tag="./ChessPieces/BlackBishop.png"
            Background="LightGray">
        <CheckBox Content="A CheckBox!" VerticalAlignment="Center"/>
    </Button>

Result:

在此处输入图片说明

Option 3: Use an Attached Property

Same as option 2, but using a property declared elsewhere, for example:

 <Button ButtonImage.Source="./ChessPieces/BlackBishop.png"
         <!-- etc -->

Option 4: Create a Custom Control:

Create a class (.cs file with no XAML) derived from Button and add a DependencyProperty to hold the image, then set the template to that and use that value.

Option 5: MVVM

Create a ButtonViewModel , or actually use a DelegateCommand declared in the ViewModel to bind the Button's properties.

Not an Option: Traverse the Visual Tree and change the Image.Source in code.

That's not something you will want to do. It's not a good approach at all.

I could go on forever, but I have to go to sleep. If you want me to elaborate on any of these approaches just let me know.

A few ways spring to mind:

  1. Access the style at runtime and traverse it to find the image
  2. Give the image a name and reference that at runtime and just change the source

The best solution I believe is to create a usercontrol and have the image source as a dependency property see: http://www.codeproject.com/Articles/224230/Exploring-the-use-of-Dependency-Properties-in-User

That way you'll have a ready-to-use "custom" control that supports what you're after and allows you to just reference it directly and use bindings, that way you avoid the messy solutions from using a style.


After discussion and expansion on requirements, please see:

How can I access ResourceDictionary in wpf from C# code?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM