WPF图像有两个来源

时间:2013-08-19 13:48:19

标签: c# wpf image

我想通过添加第二个源来扩展Image类。我想在XAML中定义第二个源(如原始源),并在鼠标进入/离开此图像时更改这些图像。

我试着用自己:

class MainMenuImageButton : Image
    {
        public static readonly DependencyProperty Source2Property;
        public ImageSource Source2 
        {
            get { return Source2; }
            set
            {
                this.MouseEnter+=new System.Windows.Input.MouseEventHandler(MainMenuImageButton_MouseEnter);
            }
        }
        public void MainMenuImageButton_MouseEnter(object sender, MouseEventArgs e)
        {
            this.Source = Source2;
        }
    }

但它不起作用,我认为我做错了。有人可以帮忙吗?

[UPDATE]

我写了这个:

class MainMenuImageButton : Image
{
    protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
    {
        var source = (BitmapSource)Source;
        var x = (int)(hitTestParameters.HitPoint.X / ActualWidth * source.PixelWidth);
        var y = (int)(hitTestParameters.HitPoint.Y / ActualHeight * source.PixelHeight);
        var pixels = new byte[4];
        source.CopyPixels(new Int32Rect(x, y, 1, 1), pixels, 4, 0);
        if (pixels[3] < 10) return null;
        return new PointHitTestResult(this, hitTestParameters.HitPoint);
    }
    public ImageSource Source1
    {
        get { return GetValue(ImageSourceProperty) as ImageSource; }
        set { base.SetValue(ImageSourceProperty, value); }
    }
    public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("Source1", typeof(ImageSource), typeof(MainMenuImageButton));
    public ImageSource Source2
    {
        get { return GetValue(ImageSource2Property) as ImageSource; }
        set { base.SetValue(ImageSource2Property, value); }
    }
    public static readonly DependencyProperty ImageSource2Property = DependencyProperty.Register("Source2", typeof(ImageSource), typeof(MainMenuImageButton));
    public MainMenuImageButton() : base() 
    {
        this.MouseEnter += new MouseEventHandler(MainMenuImageButton_MouseEnter);
        this.MouseLeave += new MouseEventHandler(MainMenuImageButton_MouseLeave);
    }

    void MainMenuImageButton_MouseLeave(object sender, MouseEventArgs e)
    {
        this.Source = this.Source1;
    }

    void MainMenuImageButton_MouseEnter(object sender, MouseEventArgs e)
    {
        this.Source = this.Source2;
    }
}

但有时它会起作用,有时会出现异常:“PresentationCore.dll中出现未处理的'System.ArgumentException'类型异常

附加信息:该值超出预期范围。“


我不确定我是否理解,但我试过这个:

class MainMenuImageButton : Image
{
    public static readonly DependencyProperty Source2Property = DependencyProperty.Register("Source2", typeof(ImageSource), typeof(MainMenuImageButton), new PropertyMetadata(true));
    public ImageSource Source2 
    {
        get { return (ImageSource)GetValue(Source2Property); }
        set
        {
            BitmapImage logo = new BitmapImage(new Uri(value.ToString(), UriKind.Relative));
            SetValue(Source2Property, logo); 
            this.MouseEnter+=new System.Windows.Input.MouseEventHandler(MainMenuImageButton_MouseEnter);
        }
    }
    public void MainMenuImageButton_MouseEnter(object sender, MouseEventArgs e)
    {
        this.Source = Source2;
    }
}

仍然没有。我做错了吗?

4 个答案:

答案 0 :(得分:4)

扩展图像是一种矫枉过正,您所要做的就是定义一种将使用触发器来交换源的样式

<Image>
  <Image.Style>
    <Style TargetType="{x:Type Image}">
      <Setter Property="Source" Value="Image1"/>
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Source" Value="Image2"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Image.Style>
</Image>

答案 1 :(得分:3)

请参阅Custom Dependency Properties article on MSDN。事件连接属于您的依赖项属性PropertyChangedCallback

我还建议使用触发器而不是事件处理。但是,这并不意味着您需要在任何想要使用它的地方复制XAML。您可以使用默认样式的图像切换触发器定义自定义控件(请参阅Control Authoring Overview中的“在主题级别定义资源”)。其中MouseOverImage是具有“Source”和“Source2”依赖项属性的Control,您可以定义此默认样式:

<Style TargetType="local:MouseOverImage">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MouseOverImage">
                <Grid>
                    <Image Name="SourceImage" Source="{TemplateBinding Source}" />
                    <Image Name="Source2Image" Source="{TemplateBinding Source2}" Visibility="Hidden" />
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="SourceImage" Property="Visibility" Value="Hidden" />
                        <Setter TargetName="Source2Image" Property="Visibility" Value="Visible" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如果使用事件处理程序,则需要存储Source的原始值,添加一个还原它的MouseLeave处理程序,并考虑用户重新分配Source或{{1在任何时候。使用具有两个单独的“Source”和“Source2”绑定的触发器解决方案,所有这些都将自动处理。

修改

  

但有时它有效,有时会有例外:“未经处理   发生在'System.ArgumentException'类型的异常   PresentationCore.dll中

     

附加信息:该值超出预期范围。“

我的猜测是Source2在源更改后但在应用于布局之前触发,因此HitTestCoreActualWidth之间存在差异。我不确定在计算中包含这些的理由(它们不应该总是相同吗?)尝试使用以下内容:

source.PixelWidth

答案 2 :(得分:1)

您无需扩展Image类来执行此操作。名为Image的{​​{1}}课程中有一个属性,您可以触发该属性来切换图片的IsMouseOver。将它放在视图中的样式中,您就可以完成所有设置。

答案 3 :(得分:0)

您需要将新属性添加为Dependency Property。您可以在MSDN的DependencyProperties Overview页面上找到更多信息,但基本的想法是:

首先创建Dependency Property

public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register(
"IsSpinning", typeof(Boolean), typeof(YourClassName), new PropertyMetadata(true));

然后你可以选择使用标准CLR属性添加包装器(仅供您自己使用):

public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

(代码示例取自链接文章)