none
Metro风格C++应用开发,如何自定义Button控件添加背景图片,每个按下和弹起显示的不一样的图片背景? RRS feed

  • 问题

  • hi,baobao

         你好,看过论坛上

    http://social.msdn.microsoft.com/Forums/zh-CN/metroappzhcn/thread/37fa7386-0406-4265-82c4-993ec7be458e

        有关此问题的讨论,在原问题上已经回复,但是考虑到原问题已经解决,重新提交一个。

    最后一步能否帮忙再详细说一说,即自己定义一个button控件,每个按下和弹起显示的不一样的图片背景。使用下面的这种需求可能很多人都有,尤其是触屏版的button,默认的效果实在是太差了,模版的方式不行,一步满足要求,二太麻烦了,是不是每一个page都要插入这么一段。

    如何给Button添加背景图片,每个按下和弹起时显示自己不一样的图片背景。

    多谢!

    2012年6月28日 11:13

答案

  • 所以我在最后回复了你可以自己创建自己的Custom Control,然后就可以进行复用了。

    可能一下还无法理解,没关系,你可以先看看官方的用户控件和自定义控件的例子:http://code.msdn.microsoft.com/windowsapps/XAML-user-and-custom-a8a9505e

    然后,再看看我的这个针对你的要求的例子。

    1. 创建一个TemplatedControl, 然后修改其继承关系:

        public sealed class ImageButton : Button
        {
            public ImageButton()
            {
                this.DefaultStyleKey = typeof(ImageButton);
            }
            public Brush PressedBackground
            {
                get { return (Brush)GetValue(PressedBackgroundProperty); }
                set { SetValue(PressedBackgroundProperty, value); }
            }
            public static readonly DependencyProperty PressedBackgroundProperty =
                DependencyProperty.Register("PressedBackground", typeof(Brush), typeof(ImageButton), new PropertyMetadata(new SolidColorBrush(Colors.Gray)));
        }


    2. 修改此custom控件的样式模板,在Themes/Generic.xaml中:

        <Style TargetType="local:ImageButton">
            <Setter Property="Background" Value="{StaticResource ButtonBackgroundThemeBrush}"/>
            <Setter Property="Foreground" Value="{StaticResource ButtonForegroundThemeBrush}"/>
            <Setter Property="BorderBrush" Value="{StaticResource ButtonBorderThemeBrush}"/>
            <Setter Property="BorderThickness" Value="{StaticResource ButtonBorderThemeThickness}"/>
            <Setter Property="Padding" Value="12,4,12,4"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="FontFamily" Value="{StaticResource ContentControlThemeFontFamily}"/>
            <Setter Property="FontWeight" Value="SemiBold"/>
            <Setter Property="FontSize" Value="{StaticResource ControlContentThemeFontSize}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:ImageButton">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverBackgroundThemeBrush}"/>
                                                </ObjectAnimationUsingKeyFrames>-->
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverForegroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=PressedBackground}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPressedForegroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBackgroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Border">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBorderThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledForegroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Focused">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualWhite"/>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualBlack"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unfocused"/>
                                    <VisualState x:Name="PointerFocused"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="3">
                                <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                            <Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="1.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1"/>
                            <Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="0.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    注意,我在Pressed的VisualState中绑定了自己定义的依赖属性。

    3.使用自己的控件:

      <local:ImageButton Content="Button">
          <local:ImageButton.Background>
              <ImageBrush .../>
          </local:ImageButton.Background>
          <local:ImageButton.PressedBackground>
              <ImageBrush .../>
          </local:ImageButton.PressedBackground>
      </local:ImageButton>

    一个例子下载,我没有用ImageBrush,仅仅是SolidColorBrush, 自己替换即可:https://skydrive.live.com/#cid=51B2FDD068799D15&id=51B2FDD068799D15%211029

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    • 已标记为答案 QitaoFan 2012年6月30日 16:14
    2012年6月29日 3:40
    版主

全部回复

  • 所以我在最后回复了你可以自己创建自己的Custom Control,然后就可以进行复用了。

    可能一下还无法理解,没关系,你可以先看看官方的用户控件和自定义控件的例子:http://code.msdn.microsoft.com/windowsapps/XAML-user-and-custom-a8a9505e

    然后,再看看我的这个针对你的要求的例子。

    1. 创建一个TemplatedControl, 然后修改其继承关系:

        public sealed class ImageButton : Button
        {
            public ImageButton()
            {
                this.DefaultStyleKey = typeof(ImageButton);
            }
            public Brush PressedBackground
            {
                get { return (Brush)GetValue(PressedBackgroundProperty); }
                set { SetValue(PressedBackgroundProperty, value); }
            }
            public static readonly DependencyProperty PressedBackgroundProperty =
                DependencyProperty.Register("PressedBackground", typeof(Brush), typeof(ImageButton), new PropertyMetadata(new SolidColorBrush(Colors.Gray)));
        }


    2. 修改此custom控件的样式模板,在Themes/Generic.xaml中:

        <Style TargetType="local:ImageButton">
            <Setter Property="Background" Value="{StaticResource ButtonBackgroundThemeBrush}"/>
            <Setter Property="Foreground" Value="{StaticResource ButtonForegroundThemeBrush}"/>
            <Setter Property="BorderBrush" Value="{StaticResource ButtonBorderThemeBrush}"/>
            <Setter Property="BorderThickness" Value="{StaticResource ButtonBorderThemeThickness}"/>
            <Setter Property="Padding" Value="12,4,12,4"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="FontFamily" Value="{StaticResource ContentControlThemeFontFamily}"/>
            <Setter Property="FontWeight" Value="SemiBold"/>
            <Setter Property="FontSize" Value="{StaticResource ControlContentThemeFontSize}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:ImageButton">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverBackgroundThemeBrush}"/>
                                                </ObjectAnimationUsingKeyFrames>-->
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverForegroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=PressedBackground}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPressedForegroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBackgroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Border">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBorderThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledForegroundThemeBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Focused">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualWhite"/>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualBlack"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unfocused"/>
                                    <VisualState x:Name="PointerFocused"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="3">
                                <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                            <Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="1.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1"/>
                            <Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="0.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    注意,我在Pressed的VisualState中绑定了自己定义的依赖属性。

    3.使用自己的控件:

      <local:ImageButton Content="Button">
          <local:ImageButton.Background>
              <ImageBrush .../>
          </local:ImageButton.Background>
          <local:ImageButton.PressedBackground>
              <ImageBrush .../>
          </local:ImageButton.PressedBackground>
      </local:ImageButton>

    一个例子下载,我没有用ImageBrush,仅仅是SolidColorBrush, 自己替换即可:https://skydrive.live.com/#cid=51B2FDD068799D15&id=51B2FDD068799D15%211029

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    • 已标记为答案 QitaoFan 2012年6月30日 16:14
    2012年6月29日 3:40
    版主
  • 虽然在转为C++时碰到了一点问题,但在参考例子XAML user and custom controls sample c++版本之后,问题解决了

    最后还是要感谢baobao指点和示例,否则这么复杂可搞不定

    下面是C++ ImageButton的代码,有需要又没时间的童鞋可以拿来直接用了 

    //
    // ImageButton.h
    // Declaration of the ImageButton class.
    //
    using namespace Windows::UI::Xaml::Controls;
    using namespace Windows::UI::Xaml::Interop;
    using namespace Windows::UI::Xaml;
    using namespace Windows::UI::Xaml::Media;
    using namespace Platform;
    #pragma once

    namespace UserAndCustomControls
    {
     public ref class ImageButton sealed : public Windows::UI::Xaml::Controls::Button
     {
     private:
      static DependencyProperty^ PressedBackgroundProperty;
     public:
      ImageButton();

      property Brush^ PressedBackground
      {
       Brush^ get() { return (Brush^)GetValue(PressedBackgroundProperty); }
       void set(Brush^ value) { SetValue(PressedBackgroundProperty, value); }
      }

     };
    }

    //
    // ImageButton.cpp
    // Implementation of the ImageButton class.
    //

    #include "pch.h"
    #include "ImageButton.h"

    using namespace UserAndCustomControls;

    using namespace Platform;
    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Collections;
    using namespace Windows::UI::Xaml;
    using namespace Windows::UI::Xaml::Controls;
    using namespace Windows::UI::Xaml::Data;
    using namespace Windows::UI::Xaml::Documents;
    using namespace Windows::UI::Xaml::Input;
    using namespace Windows::UI::Xaml::Interop;
    using namespace Windows::UI::Xaml::Media;

    // The Templated Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234235

    ImageButton::ImageButton()
    {
     DefaultStyleKey = "UserAndCustomControls.ImageButton";
    }

    DependencyProperty^ ImageButton::PressedBackgroundProperty = DependencyProperty::Register("PressedBackground", Brush::typeid, ImageButton::typeid,nullptr /*ref new PropertyMetadata(ref new SolidColorBrush(Windows::UI::Colors::Gray))*/);

     

    2012年6月30日 16:29
  • 继承button的控件,能不能有press 和 release 事件呢

    2012年7月26日 5:43
  • Bob,

    我按照你写的

    public static readonly DependencyProperty PressedBackgroundProperty =
                DependencyProperty.Register("PressedBackground", typeof(Brush), typeof(ImageButton), new PropertyMetadata(new SolidColorBrush(Colors.Gray)));

    编译发生错误: error CS0103: 当前上下文中不存在名称“Colors”

    需要using什么命名空间么?

    2012年7月26日 5:45
  • Windows::UI::Colors::Gray
    2012年7月26日 6:33
  • C++下注册依赖属性,参考:http://msdn.microsoft.com/en-us/library/windows/apps/hh920267.aspx

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us


    2012年7月26日 6:42
    版主
  • 继承button的控件,能不能有press 和 release 事件呢

    refer to http://social.msdn.microsoft.com/Forums/zh-CN/metroappzhcn/thread/1073df5a-6eb1-4747-8552-b1cf6b0beab3

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年7月26日 8:04
    版主