Отвечено WPF, работа с анимацией

  • 10 апреля 2011 г. 16:17
     
     
    Типичная проблемка, но не понял как ее реализовать, сильно уж намудрили с вроде-бы простыми элементами... Для начала, что лучше использовать для отображения анимации? RichTextBox или WebBrowser? И как вообще внести изменение содержания этих элементов? Зачем так надо было усложнять с RichTextBox... Если можно примерчик со строкой текста и анимированной картинкой из ресурсов (test.gif). Спасибо
    • Изменено Siompc 19 апреля 2011 г. 8:22
    •  

Все ответы

  • 10 апреля 2011 г. 19:04
    Отвечающий
     
     
    что лучше использовать для отображения анимации? RichTextBox или WebBrowser?

    Вопрос в корне не правильный. Для анимации в WPF не нужен специальный элемент.

    Что бы тебе ответили на вопрос по анимации, то задай вопрос конкретнее.

    На второй вопрос - если нужен именно RichTextBox, то изучай http://msdn.microsoft.com/ru-ru/library/ms748388.aspx

    Или расскажи в чем состоит задача и тебе подскажут ее решение (может RichTextBox и не нужен). С WebBrowser из 4 фреймворка еще не сталкивался, ничего сказать не смогу.

  • 11 апреля 2011 г. 9:32
     
      С кодом

    Пример добавления анимированного изображения в RichTextBox (C#):

    Xaml:

    <Window x:Class="WpfApplication20.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
      <Grid>
        <RichTextBox Name="rtb" Width="200" Height="200" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="397,45,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
      </Grid>
    </Window>
    
    

    Код:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Drawing;
    using System.Windows.Threading;
    using System.Windows.Interop;
    
    namespace WpfApplication20
    {
      /// <summary>
      /// Interaction logic for MainWindow.xaml
      /// </summary>
      public partial class MainWindow : Window
      {
        public MainWindow()
        {
          InitializeComponent();
        }
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
          AnimatedImageControl testImg = new AnimatedImageControl(@"D:\220px-Rotating_earth_(large).gif");
          Paragraph p = new Paragraph();
          p.Inlines.Add(new InlineUIContainer(testImg));
          rtb.Document.Blocks.Add(p);
        }
      }
    
      public class AnimatedImageControl : System.Windows.Controls.Image
      {
        delegate void OnFrameChangedDelegate();
        System.Drawing.Bitmap img = null;
    
        public AnimatedImageControl(string path)
        {
          img = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(path);
          Dispatcher.BeginInvoke(DispatcherPriority.Normal, new OnFrameChangedDelegate(OnUpdateSource));
          System.Drawing.ImageAnimator.Animate(img, new EventHandler(OnFrameChanged));
        }
    
        private void OnFrameChanged(object sender, EventArgs e)
        {
          Dispatcher.BeginInvoke(DispatcherPriority.Normal, new OnFrameChangedDelegate(OnFrameChangedInMainThread));
        }
        private void OnUpdateSource()
        {
          BeginInit();
          this.Source = this.GetBitmapSource(img);
          EndInit();
        }
        private void OnFrameChangedInMainThread()
        {
          BeginInit();
          System.Drawing.ImageAnimator.UpdateFrames(img);
          this.Source = this.GetBitmapSource(img);
          InvalidateVisual();
          EndInit();
        }
        private BitmapSource GetBitmapSource(Bitmap gdiBitmap)
        {
          return Imaging.CreateBitmapSourceFromHBitmap(
           gdiBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
      }
    }
    
    

    (Источник: AnimatedImageControl, пример использования)


    Для связи [mail]
  • 12 апреля 2011 г. 14:21
     
     
    Какой ужас... а в VB можно как то перевести? Он ругается практически на все... 
  • 13 апреля 2011 г. 4:51
    Отвечающий
     
     

    Это C#

    Если Дмитрий правильно тебя понял и тебе нужна именно работа с анимированным изображением (gif например), то будем его просить перевести сам класс AnimatedImageControl на VB, ибо мне и самому не помешает!!!

    Если тебе нужно что то другое, то поясняй что!

  • 13 апреля 2011 г. 5:13
     
     

    Да-да! Это как раз подходит. Необходимо вместе с текстом вставить в рич-текст-бокс анимацию. Этот вариант подходит лучше всего. Пробовал сам перевести, но понятия не имею как в VB написать это -  img = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(path)

    Возможно так:

    Dim img as  BitmapImage = System.Drawing.Image.FromFile(path)

    Но так тоже выдает много ошибок.

  • 13 апреля 2011 г. 5:24
     
     Отвечено С кодом

    1. Добавить в References dll System.Drawing

    2.

    Imports System.Windows.Threading
    Imports System.Drawing
    Imports System.Windows.Interop
    

    3.

    Public Class AnimatedImageControl
      Inherits System.Windows.Controls.Image
      Private Delegate Sub OnFrameChangedDelegate()
      Private img As System.Drawing.Bitmap = Nothing
    
      Public Sub New(path As String)
        img = DirectCast(System.Drawing.Image.FromFile(path), System.Drawing.Bitmap)
        Dispatcher.BeginInvoke(DispatcherPriority.Normal, New OnFrameChangedDelegate(AddressOf OnUpdateSource))
        System.Drawing.ImageAnimator.Animate(img, New EventHandler(AddressOf OnFrameChanged))
      End Sub
    
      Private Sub OnFrameChanged(sender As Object, e As EventArgs)
        Dispatcher.BeginInvoke(DispatcherPriority.Normal, New OnFrameChangedDelegate(AddressOf OnFrameChangedInMainThread))
      End Sub
      Private Sub OnUpdateSource()
        BeginInit()
        Me.Source = Me.GetBitmapSource(img)
        EndInit()
      End Sub
      Private Sub OnFrameChangedInMainThread()
        BeginInit()
        System.Drawing.ImageAnimator.UpdateFrames(img)
        Me.Source = Me.GetBitmapSource(img)
        InvalidateVisual()
        EndInit()
      End Sub
      Private Function GetBitmapSource(gdiBitmap As Bitmap) As BitmapSource
        Return Imaging.CreateBitmapSourceFromHBitmap(gdiBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions())
      End Function
    End Class
    

     


    Для связи [mail]
    • Предложено в качестве ответа LXGDARKMicrosoft Community Contributor, Editor 13 апреля 2011 г. 6:33
    • Помечено в качестве ответа Siompc 16 апреля 2011 г. 9:55
    • Снята пометка об ответе Siompc 19 апреля 2011 г. 8:20
    • Помечено в качестве ответа Siompc 21 апреля 2011 г. 18:26
    •  
  • 13 апреля 2011 г. 16:25
     
     

    Оо, спасибо! Последний вопрос, почему работает только так

    Public testImg As AnimatedSmilesControl = New AnimatedSmilesControl("D:\1.gif")

    если попытаться изменить -

    testImg = New AnimatedSmilesControl("D:\1.gif")

    выдает ошибку при ображщении.

  • 14 апреля 2011 г. 7:51
     
     
    Какую ошибку? и не очень понятно что и как вы пытаетесь изменить.
    Для связи [mail]
  • 14 апреля 2011 г. 13:50
     
     

    Public testImg As AnimatedSmilesControl = New AnimatedSmilesControl("D:\1.gif")

    Grid.Children.Add(testImg)

    Так работает...

     

     

    Public testImg As AnimatedSmilesControl

    testImg = New AnimatedSmilesControl("D:\1.gif")

    Grid.Children.Add(testImg)

    А так говорит что ссылается на экземпляр объекта

  • 14 апреля 2011 г. 18:03
    Отвечающий
     
     

    Сначала в классе AnimatedSmilesControl добавь конструктор New без параметров, а потом делай так

    Public testImg As New AnimatedSmilesControl

    testImg = New AnimatedSmilesControl("D:\1.gif")

    Объясню почему не работает. Первый вариант, который работает равносилен записи Public testImg As New AnimatedSmilesControl("D:\1.gif"), то есть объявляется экземпляр класса, а во втором варианте нет объявления экземпляра класса (о чем свидетельствует зеленое волнистое подчеркивание под словом testImg). Это основы объектно-ориентированного программирования!!! Не плохо бы знать такие вещи.

    • Помечено в качестве ответа Siompc 16 апреля 2011 г. 9:55
    • Снята пометка об ответе Siompc 19 апреля 2011 г. 8:11
    •  
  • 19 апреля 2011 г. 8:20
     
     
    Не работает. Не класс, ни работа с ним:

    Сначала в классе AnimatedSmilesControl добавь конструктор New без параметров, а потом делай так
    Public testImg As New AnimatedSmilesControl
    testImg = New AnimatedSmilesControl("D:\1.gif")

    Если обьявить так - Public testImg As New AnimatedSmilesControl, требует аргумент path...
    А класс анимации работает только в том случае, если анимация просто стоит и никаких действий не происходит. Что делать если надо изменить картинку на анимацию при наведении курсора? Выдает ошибку:
    В GDI+ возникла ошибка общего вида.

    Может что не так делаю? Вот код:

    Private Sub GeneralStep_MouseEnter(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles _
    GeneralPicStep.MouseEnter
    Dim Anim As New AnimatedControl(My.Computer.FileSystem.CurrentDirectory & "\Data\BU\StepOn.gif")
    If BlockStepImg(0) = False Then 'Разрешено изменение?
    GeneralPicStep.Source = Anim.Source
    End If
    End Sub

    И что делать, если необходимо изменить изображение в классе AnimatedControl не при обьявлении переменной.
    Dim Anim As AnimatedControl
    Anim = New AnimatedControl("D:\1.gif")
    Так не работает...

  • 19 апреля 2011 г. 18:34
    Отвечающий
     
     Отвечено С кодом

    Во первых приведенный код это только часть истории вырванная из контекста, поэтому не все понятно.

    Во вторых - класс AnimatedControl наследник класса Image и вот эта строка GeneralPicStep.Source = Anim.Source вообще не нужна. Там где в окне должно быть анимированное изображение нужно помещать экземпляр класса AnimatedControl

    Короче мне пока не надо было, но спешл фо ю я переделал предложенный Дмитрием класс и щас пошагово расскажу че с ним делать.

    Шаг первый: Добавляешь в проект файл класса и даешь ему название AnimatedImageControl. Содержимое заменяешь следующим кодом:

     

    Imports System.Windows.Threading
    Imports System.Drawing
    Imports System.Windows.Interop
    Public Class AnimatedImageControl
     Inherits System.Windows.Controls.Image
     Private Delegate Sub OnFrameChangedDelegate()
     Private img As System.Drawing.Bitmap = Nothing
     Dim path As String
     Public Sub New()
     End Sub
     Public WriteOnly Property AnimPath As String
      Set(ByVal value As String)
       path = value
       img = DirectCast(System.Drawing.Image.FromFile(path), System.Drawing.Bitmap)
       Me.Source = Me.GetBitmapSource(img)
      End Set
     End Property
     Public Sub StarAnimation()
      img = DirectCast(System.Drawing.Image.FromFile(path), System.Drawing.Bitmap)
      Dispatcher.BeginInvoke(DispatcherPriority.Normal, New OnFrameChangedDelegate(AddressOf OnUpdateSource))
      System.Drawing.ImageAnimator.Animate(img, New EventHandler(AddressOf OnFrameChanged))
     End Sub
     Private Sub OnFrameChanged(ByVal sender As Object, ByVal e As EventArgs)
      Dispatcher.BeginInvoke(DispatcherPriority.Normal, New OnFrameChangedDelegate(AddressOf OnFrameChangedInMainThread))
     End Sub
     Private Sub OnUpdateSource()
      BeginInit()
      Me.Source = Me.GetBitmapSource(img)
      EndInit()
     End Sub
     Private Sub OnFrameChangedInMainThread()
      BeginInit()
      System.Drawing.ImageAnimator.UpdateFrames(img)
      Me.Source = Me.GetBitmapSource(img)
      InvalidateVisual()
      EndInit()
     End Sub
     Private Function GetBitmapSource(ByVal gdiBitmap As Bitmap) As BitmapSource
      Return Imaging.CreateBitmapSourceFromHBitmap(gdiBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions())
     End Function
    End Class
    
    

     

    Класс переделан так, что бы его можно было добавлять в XALM.

    Шах второй: идешь в XAML редактор нужного тебе окошка и в свойствах самого окна добавляешь следующую строчку:

    xmlns:ac="clr-namespace:WpfApplication1" (где WpfApplication1 это имя твоего приложения)

    а в месте где тебе нужен данный контрол пишешь следующее:

     

    <ac:AnimatedImageControl x:Name="Нужное_имя" AnimPath="C:\путь к файлу.gif" Height="60"></ac:AnimatedImageControl>
    

     

    Шаг третий: так как анимация еще не запущенна нужно вызвать процедуру StarAnimation (AnimControl1.StarAnimation) в любом месте кода, например в событии Window_Loaded

    Можно было конечно сделать класс, так что бы он запускал анимацию сразу при задании пути к файлу, но тогда это мешало бы при построении интерфейса, поэтому на мой взгляд так лучше.

    Конечно это все наброски. По ходу работы могут понадобится обработчики ошибок и т.д., но это уже дело наживное


    • Помечено в качестве ответа Siompc 21 апреля 2011 г. 18:26
    •  
  • 21 апреля 2011 г. 10:28
     
     

    LXGDARK огромное спасибо! Я даже не знаю за что отвечает DirectCast ))) Уже переделал класс, остался последний вопрос. здесь изображение идет через путь на диске. А как нужно преобразовать процедуру что бы шло через ресурсы (по Uri) например (  AnimUri("/Image/Bu/BU_StepWait.gif")  )

     

    Public WriteOnly Property AnimUri As Uri
    Set(ByVal value As Uri)
    Try
    ResUri = value
      img = ????????
    Me.Source = Me.GetBitmapSource(img)
    Catch ex As Exception
    Me.Source = Nothing
    End Try
    End Set
    End Property

     Загвоздка в этом месте...


  • 21 апреля 2011 г. 11:07
    Отвечающий
     
     Отвечено С кодом
    Dim sinfo As Windows.Resources.StreamResourceInfo = Application.GetResourceStream(New Uri("/Image/Bu/BU_StepWait.gif", UriKind.Relative))
    img = System.Drawing.Image.FromStream(sinfo.Stream)
    
    • Помечено в качестве ответа Siompc 21 апреля 2011 г. 18:26
    •  
  • 21 апреля 2011 г. 18:26
     
     
    Работает! :)