2013-08-19 4 views
2

Я хотел бы расширить класс изображения, добавив второй источник. Я хочу определить второй источник в XAML (например, исходный источник) и изменить эти изображения, когда мышь входит/выходит из этого изображения.WPF Изображение с двумя источниками

Я пробовал себя с:

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; 
     } 
    } 

Но это не работает, и я думаю, что я делаю это tottaly неправильно. Может ли кто-нибудь помочь?

[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; 
    } 
} 

Но иногда это работает, а иногда и есть исключение: «Необработанное исключение типа 'System.ArgumentException' произошло в PresentationCore.dll

Дополнительная информация: Значение находится за пределами ожидаемого диапазона. "


Я не уверен, если я понял, но я попытался это:

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; 
    } 
} 

И еще ничего. Что я делаю неправильно?

+3

возможный дубликат [Как изменить изображение на парении над в WPF?] (Http://stackoverflow.com/questions/1502914/how-do-i-change-an-image-on-hover-over-in-wpf) – xdumaine

+0

У вас есть петля на get. Почему вы подключаете обработчик событий в комплекте? – Paparazzi

ответ

3

Обратитесь к Custom Dependency Properties article on MSDN. Подключение к событию относится к вашему свойству зависимостей PropertyChangedCallback.

Я также предлагаю использовать триггер вместо обработки событий. Однако это не означает, что вам нужно будет дублировать XAML везде, где вы хотите его использовать. Вы можете определить настраиваемый элемент управления с триггером переключения изображения в его стиле по умолчанию (см. «Определение ресурсов на уровне темы» в Control Authoring Overview).Где MouseOverImage является Control с «Источником» и свойством зависимостей «source2», вы можете определить стиль этого по умолчанию:

<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> 

Если вы используете обработчик событий, вам нужно будет сохранять первоначальное значение источника, добавить MouseLeave который возвращает его, а также рассмотрит случай, когда пользователь переназначает Source или Source2 в любое время. Используя триггерное решение с двумя отдельными связями «Источник» и «Источник2», все это обрабатывается автоматически.

EDIT

Но иногда это работает, а иногда и есть исключение: «необработанное исключение типа 'System.ArgumentException' произошло в PresentationCore.dll

Дополнительная информация: Стоимость находится вне ожидаемого диапазона ».

Я думаю, что HitTestCore стреляет после изменения источника, но прежде, чем он применяется к раскладке, так что есть несоответствие между ActualWidth и source.PixelWidth. Я не уверен в целесообразности включения их в расчет (они не должны всегда быть такой же?) Попробуйте просто используя:

var x = (int)hitTestParameters.HitPoint.X; 
var y = (int)hitTestParameters.HitPoint.Y; 
+0

Но я также хотите переопределить метод HitTestCore, чтобы реагировать только с непрозрачным полем и называть его как кнопку. – petros

+0

@petros Возможно, было бы проще расширить изображение. Я бы пошел с отдельным свойством для определения «нормального» источника и использовал [SetBinding] (http://msdn.microsoft.com/en-us/library/system.windows.data.bindingoperations.setbinding.aspx) в обработчиках 'MouseEnter' /' MouseLeave' для привязки 'Source' к' Source1' или 'Source2'. Таким образом, оба свойства могут быть связаны независимо друг от друга без перезаписи другого при перемещении мыши. – nmclean

+0

Я отредактировал мой вопрос. Пожалуйста, посмотрите – petros

1

Для этого вам не нужно расширять класс Image. Существует свойство в классе Image под названием IsMouseOver, которое вы можете включить, чтобы переключить Source вашего изображения. Поместите это в стиле на ваш взгляд, и все будет готово.

+0

Да, но я буду часто использовать этот класс, поэтому я хочу это сделать, только определяя изображение fila – petros

0

Вам необходимо добавить новую недвижимость как: Dependency Property. Вы можете узнать больше из DependencyProperties Overview страницы в MSDN, но основная идея заключается в следующем:

Вы сначала создать 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); } 
} 

(код был взят из связанной статьи)

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> 
+0

Но где выбрать Image1 и Image2? – petros

+0

@petros вы указываете путь к 'Image1' и' Image2' в своем стиле. Вы также можете привязываться к «ImageSource» на вашей модели просмотра или в коде вместо этого, если вы не хотите жестко указывать путь ресурса изображения. – Thelonias

+0

И если я хочу использовать этот стиль более чем в одном cotrol? Должен ли я писать разные стили для каждого из них? (например, у меня есть 2 элемента управления изображением, и у каждого из них два разных источника) – petros

Смежные вопросы