【问题标题】:Windows Phone 8 - Two-State ImageButton TemplateWindows Phone 8 - 两态 ImageButton 模板
【发布时间】:2013-09-23 05:21:29
【问题描述】:

现在我正试图弄清楚如何为具有两种状态(按下和正常)的 ImageButton 创建一个模板,并为每个状态创建一个 Image

  1. 状态正常:显示图片“buttonname.png”,隐藏“buttonname_pressed.png”

  2. 按下状态:隐藏图片“buttonname.png”,显示“buttonname_pressed.png”

所以我在Application.Resources 中创建了一个新的Style

Application.Resources:

<Style x:Key="ImageButton" TargetType="Button">

    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="BorderThickness" Value="0"/>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent" Height="90">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imageNormal">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imagePressed">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imageNormal">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imagePressed">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>

                    <Image x:Name="imageNormal"  Source="{Binding ???}"  Stretch="UniformToFill" />
                    <Image x:Name="imagePressed" Source="{Binding ???}" Stretch="UniformToFill" />

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

现在我想用不同的图像创建 3 个不同的ImageButtons,这是我不明白的。 (°へ°)

我尝试使用BindingAttachedProperty...

图片源的绑定:

Source="{Binding SourceNormal, RelativeSource={RelativeSource TemplatedParent}}"

附加属性:

namespace HTML5App1.Resources.AttachedProperty
{
    public static class ImageButton
    {
        /////////////////////// SourceNormal /////////////////////////////////////////////////////

        //----------------------------------------------------------------------------------------
        public static readonly DependencyProperty SourceNormal = DependencyProperty.RegisterAttached(
            "SourceNormal",
            typeof(string),
            typeof(ImageButton),
            new PropertyMetadata(null)
        );

        public static string GetSourceNormal(UIElement element)
        {
            if (element == null)
            {
                new ArgumentNullException("element");
            }
            return (string)element.GetValue(SourceNormal);
        }

        public static void SetSourceNormal(UIElement element, string value)
        {
            if (element == null)
            {
                new ArgumentNullException("element");
            }

            element.SetValue(SourceNormal, value);
        }
        //----------------------------------------------------------------------------------------

        /////////////////////// SourcePressed ////////////////////////////////////////////////////

        //----------------------------------------------------------------------------------------
        public static readonly DependencyProperty SourcePressed = DependencyProperty.RegisterAttached(
            "SourcePressed",
            typeof(string),
            typeof(ImageButton),
            new PropertyMetadata(null)
        );

        public static string GetSourcePressed(UIElement element)
        {
            if (element == null)
            {
                new ArgumentNullException("element");
            }
            return (string)element.GetValue(SourcePressed);
        }

        public static void SetSourcePressed(UIElement element, string value)
        {
            if (element == null)
            {
                new ArgumentNullException("element");
            }

            element.SetValue(SourcePressed, value);
        }
        //----------------------------------------------------------------------------------------
    }
}

MainPage.xaml:

xmlns:local="clr-namespace:HTML5App1.Resources.AttachedProperty"

<Button
    Style="{StaticResource ImageButton}"
    local:ImageButton.SourceNormal="/Assets/Images/button.png"
    local:ImageButton.SourcePressed="/Assets/Images/button_pressed.png"
    Grid.Column="1"
    Click="Button_Clicked"
    />

如果我构建应用程序,我会收到两个绑定的错误消息:

An exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.ni.dll and wasn't handled before a managed/native boundary
System.Windows.Data Error: BindingExpression path error: 'SourceNormal' property not found on 'System.Windows.Controls.Button' 'System.Windows.Controls.Button' (HashCode=45028263). BindingExpression: Path='SourceNormal' DataItem='System.Windows.Controls.Button' (HashCode=45028263); target element is 'System.Windows.Controls.Image' (Name='imageNormal'); target property is 'Source' (type 'System.Windows.Media.ImageSource')..
System.Windows.Data Error: BindingExpression path error: 'SourcePressed' property not found on 'System.Windows.Controls.Button' 'System.Windows.Controls.Button' (HashCode=45028263). BindingExpression: Path='SourcePressed' DataItem='System.Windows.Controls.Button' (HashCode=45028263); target element is 'System.Windows.Controls.Image' (Name='imagePressed'); target property is 'Source' (type 'System.Windows.Media.ImageSource')..

但我不知道我做错了什么 - 有人能指出我正确的方向吗?

其他问题:

  • 是否有一种“更简单”的方法可以从 Button 创建 ImageButton 模板 - 我可以访问 Button 的 NormalPressed VisualState 或收听它并更改 Image.Source(如果是)正常还是按下?

  • 是否有一种“更简单”的方式来访问Button 中的Grid 中的Image.Source,而不使用Bindings(在XAML 或C# 中)?

  • 有没有很好的 XAML 绑定和模板教程,我是 XAML 的初学者

提前致谢;)

【问题讨论】:

  • 为什么不直接编辑ToggleButton 的模板来满足您的目的呢?然后你就有了你所有的状态,你可以把你的图片放进去。
  • @ChrisW。我不认为 ToggleButton 是正确的,切换按钮会是,如果当您单击它时显示一个图像,然后您再次单击它会显示另一个图像(不是按下也不是按下状态)
  • @ChrisW。谢谢你的提示,但正如 Benoit Catherinet 所说,我需要不同的按下状态(正常、按下),我可能想为禁用状态添加图像。

标签: c# xaml windows-phone-8 windows-phone


【解决方案1】:

以下应该有效:

<Image x:Name="imageNormal"  Source="{TemplateBinding local:ImageButton.SourcePressed}"  Stretch="UniformToFill" />

另外,您应该使用 ImageSource,而不是使用字符串作为两个附加属性的类型。

在回答您的其他问题时,您可以通过创建自定义控件继承按钮在代码中执行此操作,然后您可以使用所谓的 TemplatedPart 按名称访问样式内的所有元素。请参阅示例there(它是 WPF,但它对 wp 的工作方式完全相同)。但无论如何,我认为你目前的做法是正确的。

关于文章: 这个msdn documention 提供了一些示例的良好开端,但不要谈论更高级的绑定场景

在此处编辑是我测试并为我工作的完整代码:

依赖属性(将字符串切换到 ImageSource 并为 dep 属性和实际属性使用不同的名称):

public static class ImageButton
{



    /////////////////////// SourceNormal /////////////////////////////////////////////////////

    //----------------------------------------------------------------------------------------
    public static readonly DependencyProperty SourceNormalProperty = DependencyProperty.RegisterAttached(
        "SourceNormal",
        typeof(ImageSource),
        typeof(ImageButton),
        new PropertyMetadata(null)
    );

    public static ImageSource GetSourceNormal(UIElement element)
    {
        if (element == null)
        {
            new ArgumentNullException("element");
        }
        return (ImageSource)element.GetValue(SourceNormalProperty);
    }

    public static void SetSourceNormal(UIElement element, ImageSource value)
    {
        if (element == null)
        {
            new ArgumentNullException("element");
        }

        element.SetValue(SourceNormalProperty, value);
    }
    //----------------------------------------------------------------------------------------

    /////////////////////// SourcePressed ////////////////////////////////////////////////////

    //----------------------------------------------------------------------------------------
    public static readonly DependencyProperty SourcePressedProperty = DependencyProperty.RegisterAttached(
        "SourcePressed",
        typeof(ImageSource),
        typeof(ImageButton),
        new PropertyMetadata(null)
    );

    public static ImageSource GetSourcePressed(UIElement element)
    {
        if (element == null)
        {
            new ArgumentNullException("element");
        }
        return (ImageSource)element.GetValue(SourcePressedProperty);
    }

    public static void SetSourcePressed(UIElement element, ImageSource value)
    {
        if (element == null)
        {
            new ArgumentNullException("element");
        }

        element.SetValue(SourcePressedProperty, value);
    }
    //----------------------------------------------------------------------------------------
}

样式(只使用上面解释的 TemplateBinding):

<Style x:Key="ImageButton" TargetType="Button">

        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="BorderThickness" Value="0"/>

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid Background="Transparent" Height="90">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imageNormal">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imagePressed">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imageNormal">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imagePressed">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <Image x:Name="imageNormal"  Source="{TemplateBinding local:ImageButton.SourceNormal}"  Stretch="UniformToFill" />
                        <Image x:Name="imagePressed" Source="{TemplateBinding local:ImageButton.SourcePressed}" Stretch="UniformToFill" />

                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

按钮(不变):

<Button Style="{StaticResource ImageButton  }" 
                local:ImageButton.SourceNormal="/Assets/ApplicationIcon.png"
                local:ImageButton.SourcePressed="/Assets/Tiles/FlipCycleTileLarge.png"/>

【讨论】:

  • 我唯一得到的是一个错误:The property "SourceNormal" is not a DependencyProperty. To be used in markup, non-attached properties must be exposed on the target type with an accessible instance property "SourceNormal". For attached properties, the declaring type must provide static "GetSourceNormal" and "SetSourceNormal" methods. ...\HTML5App1\App.xaml
  • 用我测试和为我工作的完整源代码更新了我的回复
  • 这些错误只是设计者的错误,如果您关闭并重新打开 xaml 文件,它们可能会消失。
  • 您可以只使用“标准”属性。对于大小,只需使用 Padding 作为图像的边距,并使用 Horizo​​ntalContentAlignement 和 VerticalContentAlignement 对齐:
  • 至于文档,这篇关于创建自定义用户控件geekchamp.com/articles/creating-a-wp7-custom-control-in-7-steps 的文章是关于附加属性的文章:silverlightshow.net/items/…(它基于 silverlight,但由于 wp “基于”silverlight 它完全适用一样)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 2014-06-12
相关资源
最近更新 更多