2017-02-28 208 views
0

我想根據增加的參數創建一個用顏色填充內部的容器。根據值更改高度

例如我創建了下面的例子: 主窗口:

<Window x:Class="WpfApplication1.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> 
    <Border BorderBrush="Black" BorderThickness="1" Width="100" Height="200"> 
     <Rectangle VerticalAlignment="Bottom" Height="{Binding Height}" Width="100" Fill="Red" MaxHeight="200"/> 
    </Border> 
</Grid> 

Engine.cs:

class Engine 
{ 
    public ViewModel viewModel = new ViewModel(); 

    public void process() 
    { 
     Thread a = new Thread(() => 
     { 
      while (viewModel.Height < 200) 
      { 
       ChangeHeight(); 
       Thread.Sleep(1000); 
      } 
     }); 
     a.IsBackground = true; 
     a.Start(); 

    } 
    public void ChangeHeight() 
    { 
     viewModel.Height++;    
    } 
} 

視圖模型是DataContext的。它工作的很好,但我認爲比我做得更好。 此外,我需要在ChangeHeight()之間進行轉換,以保持平滑,這意味着此處需要動畫。

有沒有什麼好的例子或指導?

UPDATE 我添加視圖模型的代碼:

namespace WpfApplication1 

{ 公共類視圖模型:INotifyPropertyChanged的 { 私人INT m_height = 0; public int Height { get {return m_height; } set { m_height = value; NotifyPropertyChanged(「Height」); } }

#region "PropertyChanged Event" 
    public event PropertyChangedEventHandler PropertyChanged; 

    private void NotifyPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
    #endregion 
} 

}

+0

您是否在ViewModel中實現了'INotifyPropertyChanged'?你可以將其代碼添加到問題中嗎? – CKII

+0

你爲什麼覺得它不光滑?這裏發生了什麼。你可以添加更多的細節。 – Versatile

+0

請參閱:http://stackoverflow.com/questions/3762576/wpf-backgroundworker-vs-dispatcher – Versatile

回答

1

相反編程動畫視圖模型屬性的,可能必須在一個動畫目標屬性例如像的視圖附加屬性Height

public static class Animated 
{ 
    private static Duration duration = TimeSpan.FromSeconds(5); 

    public static readonly DependencyProperty HeightProperty = 
     DependencyProperty.RegisterAttached(
      "Height", typeof(double), typeof(Animated), 
      new PropertyMetadata(HeightPropertyChanged)); 

    public static double GetHeight(DependencyObject obj) 
    { 
     return (double)obj.GetValue(HeightProperty); 
    } 

    public static void SetHeight(DependencyObject obj, double value) 
    { 
     obj.SetValue(HeightProperty, value); 
    } 

    private static void HeightPropertyChanged(
     DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     var element = obj as FrameworkElement; 

     if (element != null) 
     { 
      var to = (double)e.NewValue; 
      var animation = double.IsNaN(element.Height) 
       ? new DoubleAnimation(0, to, duration) 
       : new DoubleAnimation(to, duration); 

      element.BeginAnimation(FrameworkElement.HeightProperty, animation); 
     } 
    } 
} 

你會用它在XAML這樣的:

<Rectangle Fill="Red" Width="100" Height="0" 
    local:Animated.Height="{Binding TargetHeight}"/> 

,只是設置TargetHeight視圖模型屬性設置爲所需的目標值。

+0

它工作得很好,我只是想了解一些東西,我試圖改變它將有寬度Propety而不是高度的動畫。如何做呢? – Joe

+0

將'FrameworkElement.WidthProperty'傳遞給BeginAnimation(在另一個附屬屬性的PropertyChangedCallback中)。請注意,動畫持續時間也可以聲明爲附加屬性,以便它可以在XAML中設置。 – Clemens

+0

但是在xaml中我可以添加本地:Animated.Width?我試過,但是我看不到這個屬性 – Joe

0

使用純動畫

<Border BorderBrush="Black" BorderThickness="1" Width="100" > 
     <Rectangle VerticalAlignment="Bottom" Height="50" Width="100" Fill="Red" > 
      <Rectangle.Triggers> 
       <EventTrigger RoutedEvent="Loaded"> 
        <BeginStoryboard> 
         <Storyboard Storyboard.TargetProperty="Height"> 
          <DoubleAnimation From="0" To="{Binding Height}" Duration="0:0:20"/> 
         </Storyboard> 
        </BeginStoryboard> 
       </EventTrigger> 
      </Rectangle.Triggers> 
     </Rectangle> 
    </Border> 

重構當前的做法,使用Taskasync/await這是現代的方式來編寫多線程程序。

private void Button_Click_1(object sender, RoutedEventArgs e) 
    { 
     Task.Factory.StartNew(() => { App.Current.Dispatcher.Invoke(async() => 
      { 
       while (this.Height < 200) 
       { 
        await Task.Delay(1000); 
        ++viewModel.Height; 
       } 
      }); 
     }); 
    }