【问题标题】:Change height according to value根据值改变高度
【发布时间】:2017-07-19 13:23:40
【问题描述】:

我想根据增加的参数创建一个用颜色填充内部的容器。

例如,我创建了以下示例: 主窗口:

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

ViewModel 是数据上下文。它工作得很好,但我认为有些东西比我做的要好得多。 此外,我需要 ChangeHeight() 之间的传输平滑,这意味着这里需要动画。

有什么好的例子或指导吗?

更新 我正在添加视图模型代码:

namespace WpfApplication1

{ 公共类 ViewModel:INotifyPropertyChanged { 私人 int m_height = 0; 公共 int 高度 { 得到 { 返回 m_height; } 放 { m_height = 值; NotifyPropertyChanged("身高"); } }

    #region "PropertyChanged Event"
    public event PropertyChangedEventHandler PropertyChanged;

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

}

【问题讨论】:

  • 你在 ViewModel 中实现了INotifyPropertyChanged 吗?您可以将其代码添加到问题中吗?
  • 为什么感觉不流畅?这里发生了什么。你能补充更多细节吗?
  • 谢谢你的回复,CKII-我已经为我的问题添加了一个更新 Versatile - 如果我将高度增加 15 而不是 1,它将跳到我提到的高度,我需要它顺利成长。

标签: c# wpf


【解决方案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 视图模型属性设置为所需的目标值。

【讨论】:

  • 效果很好我只是想了解一些东西,我试图更改动画,使其具有宽度属性而不是高度。怎么办?
  • FrameworkElement.WidthProperty 传递给 BeginAnimation(在另一个附加属性的 PropertyChangedCallback 中)。请注意,动画持续时间也可以声明为附加属性,以便可以在 XAML 中设置。
  • 但是我可以在 xaml 中添加 local:Animated.Width 吗?我试过了,但我看不到这个属性
  • 通过复制上面的所有代码并将每次出现的“高度”替换为“宽度”来添加另一个名为 Width 的附加属性。有关详细信息,请参阅 MSDN 上的Attached Properties Overview 文章。
【解决方案2】:

使用纯动画

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    相关资源
    最近更新 更多