views:

324

answers:

2

Hey, I was figuring out how to create an image button template in C# WPF, and I came upon this . This seems really useful to me except for two problems:

  1. I want to be able to change the images dynamically in the C# codebehind, as this button will be using images that I am loading dynamically through XML documents.
  2. FIXED I'm getting the error that "The name 'InitializeComponent' does not exist in the current context". Here is my code (note, I am not having a disabled image, only a pressed and a normal. the Normal.png and the other one are just placeholders.

I was hoping to use this in a few places, but I can always create a few different versions. However, I need the images to load dynamically and I'm not able to find out how to make an image I specify in my C# codebehind basically act as a button. Thanks

NOTE: I'm able to get the button to work well, except for the changing the image source part. this code is what I have now.

        <Button x:Class="CFYLauncher.PageNavButton"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <Grid>
                <Image x:Name="NormalImg" Source="\img\btn_arrow.png"/>
                <Image x:Name="PressedImg" Source="\img\btn_arrow_selected.png" Visibility="Hidden"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsPressed" Value="True">
                    <Setter TargetName="NormalImg" Property="Visibility" Value="Hidden"/>
                    <Setter TargetName="PressedImg" Property="Visibility" Value="Visible"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>

with codebehind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

    namespace CFYLauncher
{
    /// <summary>
    /// Interaction logic for PageNavButton.xaml
    /// </summary>
    public partial class PageNavButton : Button
    {
        public PageNavButton()
        {
            InitializeComponent();
        }

        public string ImageUri
        {
            set
            {
                this.NormalImg.Source = new BitmapImage(value);
            }
        }

    }
}

As stated below in the reply to Tom Carver's help, I'm getting two major problems with this code:

  1. "Error 1 'CFYLauncher.PageNavButton' does not contain a definition for 'NormalImg' and no extension method 'NormalImg' accepting a first argument of type 'CFYLauncher.PageNavButton' could be found (are you missing a using directive or an assembly reference?)
  2. "Error 2 The best overloaded method match for 'System.Windows.Media.Imaging.BitmapImage.BitmapImage(System.Uri)' has some invalid arguments" and "Cannot convert from 'string' to 'System.Uri'

When I change 'public string ImageUri' to 'public Uri ImageUri' the 2 errors in 2) go away, but it still can't find NormalImg, which doesn't make sense to me, because it's right there.. I must be missing something really obvious

A: 

To fix the error message, either change the namespace to TestWpfApplication or change the x:Class to "CFYLauncher.PageNavButton"

SteveCav
Thanks, I'm stupid and didn't check the namespace when I copied the code over from the other question
Andrew
A: 

In reverse order:

2) as SteveCav says, your XAML and cs files have different namespaces, your error "The name 'InitializeComponent' does not exist in the current context" generally means the code-behind and XAML files haven;t been matched by the compiler.

1) to change the image at runtime, add an x:Id x:Name attribute to one of the images, and set the Source property at runtime (note in C# you can;t just set it to the path, instead set it to a BitmapImage initialized with the path instead)


<Image Source="{Binding ImageUri}" Visibility="Hidden" />

myImage.Source = new BitmapImage(where my Uri is);

It looks from the comment like you want to set it from outside the template, in which case I'd recommend adding a public property:


public Uri ImageUri { get; set;}

Then your calling code can just call myButton.ImageUri = Uri for my image

Tom Carver
Thanks! I'm a bit confused about the x:Id attribute. I'm able to set x:Uid but not Id. I've tried setting x:Name="NormalImg" but I can't find it in C#. Right now I'm using myButton(a PageNavButton) and saying myButton.NormalImg.Source = new BitmapImage(*where my Uri is*) but it's saying it doesn't contain a definition for NormalImg. I'm pretty new to WPF and I'm looking for everything online, am I missing something completely?
Andrew
sorry my mistake on the x:Id/x:Name business. I've updated my post to hopefully match what you were after?
Tom Carver
That's exactly what I'm looking for, thanks! Unfortunately, it won't let me set a Name and a x:Name at the same time so I have <Image x:Name="NormalImg" Source="\img\btn_arrow.png"/> . For some reason, my code, which sets NormalImg.Source = new BitmapImage(value); gives me 2 errors. It tells me NormalImg doesn't exist within the context, even though it's in the XAML, and I can't convert a string to Uri, but if I replace 'public string Uri' up top with 'public Uri ImageUri', it doesn't give me a problem.
Andrew
Ignore that comment, I posted a more readable version up top.
Andrew
Hi Andrew, after all my mistakes I thought I'd run it up to see for myself. The issue is that your named control is inside a ControlTemplate - controls in this template are generated for every control using the template, so the name can't be used to reference them. For this scenario, I would change the code as above.
Tom Carver