2017-02-28 115 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; 
       } 
      }); 
     }); 
    }