Windows Phone 8 usercontrol imagebutton with diffe

2019-08-06 10:54发布

I'm new to Windows Phone 8 Development (You can say informed noob looking for answers) and I'm looking for help with the following problem:

I have usercontrol - more specifically a button containing Image and Text. I would like that button to have following properties:

  • ContentImageNormal - that would be image that displays when the button is enabled
  • ContentImageDisabled - That would be image that is dispalyed when the button is disabled

What i have now is usercontrol added in my project in folder UserControls, which I am able to use. I have created a style for it and changed the disabled button's backgeround etc.

What would i like to know:

  • How to change the code-behind and other stuff needed so that I can use it as desired below?

(I will use the button six times in my program and i would like to use this usercontrol as a kind of template for it - to prepare it so I just specify ImageSources for both states and it will do the rest)

EXAMPLE OF DESIRED USAGE:

<UserControls:MainPageButton ContentText="Log In" ContentImageNormal="/ImagePathOrResourceETC.png" ContentImageDisabled="/ImagePathOrResourceETC.png"/>

XAML I have:

    <UserControl x:Class="ProjectNameSpace.UserControls.MainPageButton">
        <Grid x:Name="LayoutRoot">
            <Button >
                <Button.Content>
                    <Grid>
                        ...omitted...
                        <Image x:Name="ContentImageHolder" ... />
                        <TextBlock x:Name="ContentTextBlock"  .../>
                    </Grid>
                </Button.Content>
            </Button>
        </Grid>
    </UserControl>

C# code-behind I currently have:

...usings omitted...
public partial class MainPageButton : UserControl
{
    ...constructor and text setting omitted for brevity...
    public ImageSource ContentImage
    {
        get
        {
            return ContentImageHolder.Source;
        }
        set
        {
            ContentImageHolder.Source = value;
        }
    }
}
}

4条回答
男人必须洒脱
2楼-- · 2019-08-06 11:29

It seem that what you are really trying to do is create a CustomControl not a UserControl. So me I will create a custom Control inheriting from Button instead, and use the button visual state to switch between the two image. Here is an implementation of that: Add this Style in ThemeS/Generic.xaml

<Style  TargetType="ButtonWithImage">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
        <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
        <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
        <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
        <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMedium}"/>
        <Setter Property="Padding" Value="10,5,10,6"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid Background="Transparent">

                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver"/>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneButtonBasePressedForegroundBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="enablebleImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="disableImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">
                            <Grid>
                                <Image x:Name="disableImage" Source="{TemplateBinding EnableImageSource}" Visibility="Collapsed"/>
                                <Image x:Name="enablebleImage"  Source="{TemplateBinding DisableImageSource}"/>
                              <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Grid>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

and define the following class:

public class ButtonWithImage :Button
{
    public static readonly DependencyProperty DisableImageSourceProperty =
        DependencyProperty.Register("DisableImageSource", typeof (ImageSource), typeof (ButtonWithImage), new PropertyMetadata(default(ImageSource)));

    public ImageSource DisableImageSource
    {
        get { return (ImageSource) GetValue(DisableImageSourceProperty); }
        set { SetValue(DisableImageSourceProperty, value); }
    }

    public static readonly DependencyProperty EnableImageSourceProperty =
        DependencyProperty.Register("EnableImageSource", typeof (ImageSource), typeof (ButtonWithImage), new PropertyMetadata(default(ImageSource)));

    public ImageSource EnableImageSource
    {
        get { return (ImageSource) GetValue(EnableImageSourceProperty); }
        set { SetValue(EnableImageSourceProperty, value); }
    }


    public ButtonWithImage()
    {
        this.DefaultStyleKey = typeof (Button);

    }
}
查看更多
仙女界的扛把子
3楼-- · 2019-08-06 11:31

This is pretty trivial to whip up (well, it is for me, because i've got tons of snippets for most of the hard stuff), so here it is as a custom UserControl.

First, create your user control with your image. Yay.

<UserControl x:Class="CustomImageControl.Controls.ThreeWay"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" >
    <Image
        x:Name="derpImage" />
</UserControl>

extra hard, there.

Next, in the codebehind you have to do the following things. First, create DependencyProperties for each type of image representing whatever state you have. In my example, I'm omitting the InactiveImage and DerpImage properties for space reasons. You can see how the ActiveImage works. Next, you create a DependencyProperty for the state of the control. In the example I have a State enum that defines this, but you can do whatever you want. On change, I examine the new value and change the image as necessary. Easy.

public partial class ThreeWay : UserControl
{
    #region ActiveImage
    public static readonly DependencyProperty ActiveImageProperty =
        DependencyProperty.Register(
            "ActiveImage",
            typeof(ImageSource),
            typeof(ThreeWay),
            new UIPropertyMetadata());

    public ImageSource ActiveImage
    {
        get { return (ImageSource)GetValue(ActiveImageProperty); }
        set { SetValue(ActiveImageProperty, value); }
    }
    #endregion

    //InactiveImage and DerpImage snipped to keep this short

    #region ImageState
    public static readonly DependencyProperty ImageStateProperty =
        DependencyProperty.Register(
            "ImageState",
            typeof(State),
            typeof(ThreeWay),
            new UIPropertyMetadata(State.Derp, OnImageStatePropertyChanged));

    private static void OnImageStatePropertyChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as ThreeWay).OnImageStateChanged(
          e.OldValue as State, e.NewValue as State);
    }

    private void OnImageStateChanged(State oldValue, State newValue)
    {
        switch(newValue)
        {
            case State.Active:
                this.derpImage.Source = ActiveImage;
                break;
            case State.Inactive:
                this.derpImage.Source = InactiveImage;
                break;
            case State.Derp:
                this.derpImage.Source = DerpImage;
                break;
        }
    }

    public State ImageState
    {
        get { return (State)GetValue(ImageStateProperty); }
        set { SetValue(ImageStateProperty, value); }
    }
    #endregion

    public ThreeWay()
    {
        InitializeComponent();
    }

    public enum State
    {
        Active,
        Inactive,
        Derp
    }
}

And that's it. You would use it like this:

<cc:ThreeWay xmlns:cc="clr-namespace:CustomImageControl.Controls"
             ActiveImage="active.png"
             InactiveImage="inactive.png"
             DerpImage="derp.jpg"
             ImageState="{Binding State}" />

This assumes the DataContext is an instance with a property called State of type ThreeWay.State. If not, a custom converter can be used to convert between whatever (nullable bool?) to the correct type.

查看更多
在下西门庆
4楼-- · 2019-08-06 11:48

Jan,

For your problem, you are just missing one thing.

In your UserControl you have to create the DependencyProperties like this:

 public static readonly DependencyProperty ContentImageNormalProperty =

            DependencyProperty.Register("ContentImageNormal",

                typeof(ImageSource ),

                typeof(MainPageButton));

Then your property should be something like this:

     public string ContentImageNormal{ get { return (ImageSource)this.GetValue(ContentImageNormalProperty); } 
set { this.SetValue(ContentImageNormalProperty, value); } }

Do this for each property you want to set...

See this example: http://stevenhollidge.blogspot.pt/2012/03/dependency-properties-in-user-control.html

I hope this helps you.

Regards, Sérgio Monteiro

查看更多
贼婆χ
5楼-- · 2019-08-06 11:48

You could have a simple binding to Image and to Text.

For your example:

<Button name="buttonTest">
                <Button.Content>
                    <Grid>
                        ...omitted...
                        <Image x:Name="ContentImageHolder" Source="{Binding ElementName=buttonTest, Path=IsEnabled, Converter ={StaticResource convertButton}}" Grid.Row="0" />
                        <TextBlock x:Name="ContentTextBlock"  Text="My Sample Text" Grid.Row="1" FontSize="{StaticResource PhoneFontSizeNormal}" FontFamily="{StaticResource PhoneFontFamilyNormal}" Foreground="{StaticResource PhoneForegroundBrush}" TextAlignment="Center"/>
                    </Grid>

Then you would create a Converter that would receive as value a True or False (enabled or not), and then return the image you want in each state.

Your converter could be something like

  public class ButtonImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {


            if((bool) value)
return  CreateImage("pack://application:,,,/ButtonEnabled.ico"); // url should be correct
else  return  CreateImage("pack://application:,,,/ButtonDisable.ico");

        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }

        /// <summary>
        /// Method to create an image to bind to icons in treeview
        /// </summary>
        /// <param name="uriToImage">uri to image in folder.</param>
        /// <returns>a bitmap image to bind to image source in tree view</returns>
        private BitmapImage CreateImage(string uriToImage)
        {
            if (!string.IsNullOrEmpty(uriToImage))
            {
                BitmapImage genericBitmap = new BitmapImage();
                genericBitmap.BeginInit();
                genericBitmap.UriSource = new Uri(uriToImage);
                genericBitmap.EndInit();
                return genericBitmap;
            }

            return null;

        }
    }

For the Text, if it is dependant on any property you could also do the same.

查看更多
登录 后发表回答