【问题标题】:WPF, Opacity and ThreadsWPF、不透明度和线程
【发布时间】:2011-08-18 21:58:08
【问题描述】:

我有两个重叠(在相同位置,具有相同大小)的 MediaElement。它们将包含图像。一个元素的不透明度将设置为 1.0,而另一个元素的不透明度将设置为 0.0。这里的想法是幻灯片类型交易的简单过渡。当需要显示下一张幻灯片时,背景元素会加载一张图片,并且两个元素的不透明度会逐渐切换。

我尝试(成功地)使用 System.Timers 实现此行为,但发现在同一应用程序中拥有多个任意数量的计时器会导致 .NET 随机生成并将 timer_elapsed 的控制权交给几个不同的线程。这导致了不可预测的结果,并且通常让我怀疑自己的理智。

所以,我决定做同样的事情,但使用 System.Threads 和它们的 Sleep 函数。无论出于何种原因,逐渐循环不透明度与疯狂的计时器完美配合,但与线程完全失败。它以一种荒谬的方式失败了。两个元素的不透明度确实发生了变化,但两者之间没有变化。元素以 1.0 或 0.0 的不透明度显示。否则我会注意到大约一半的图片没有被循环播放。

经过多次谷歌搜索,我认为可能发生不透明度更改的线程的优先级以某种方式阻止 UI 元素立即呈现。但后来我回想起来,因为我在媒体元素上使用调度程序调用,所以所有的操作都发生在主线程上,所以不会有什么不同。

考虑以下代码:https://gist.github.com/956093

【问题讨论】:

  • 为什么要手动而不是通过情节提要动画?
  • 缺乏 WPF 经验。考虑到在整个过程中我被要求忍受的废话的数量,我可能最终还是会走那条路。我真的很想知道为什么这种合乎逻辑的东西不起作用。

标签: c# wpf multithreading opacity


【解决方案1】:

按照建议,您应该使用原生动画;我以前也遇到过这个线程问题,一般来说,我尽量避免使用调度程序,我几乎只在必须时使用它们来修改数据(例如 ObservableCollection 不能在后台线程中修改,不知道任何其他示例实际上)。

你仍然可以使用普通线程,如果你使用绑定来更新 UIElements 可以很好地绕过调度问题。

动画示例:

<Grid Name="testGrid" Tag="2">
    <Grid.Resources>
        <Storyboard x:Key="FadeAnim2to1">
            <DoubleAnimation Storyboard.Target="{x:Reference img1}"
                             Storyboard.TargetProperty="Opacity"
                             Duration="0:0:1" To="1"/>
            <DoubleAnimation Storyboard.Target="{x:Reference img2}"
                             Storyboard.TargetProperty="Opacity"
                             Duration="0:0:1" To="0"/>
        </Storyboard>
        <Storyboard x:Key="FadeAnim1to2">
            <DoubleAnimation Storyboard.Target="{x:Reference img1}"
                             Storyboard.TargetProperty="Opacity"
                             Duration="0:0:1" To="0"/>
            <DoubleAnimation Storyboard.Target="{x:Reference img2}"
                             Storyboard.TargetProperty="Opacity"
                             Duration="0:0:1" To="1"/>
        </Storyboard>
    </Grid.Resources>
    <Image x:Name="img1" Source="Images/Default.ico" Width="200" Height="200" Opacity="0"/>
    <Image x:Name="img2" Source="Images/Error.ico" Width="200" Height="200"/>
</Grid>
<Button Content="Fade" Click="Button1_Click"/>
private void Button1_Click(object sender, RoutedEventArgs e)
{
    Storyboard anim;
    if ((string)testGrid.Tag == "1") //This is just for brevity, you should of course not use the Tag to store state information, let alone number strings
    {
        anim = testGrid.Resources["FadeAnim1to2"] as Storyboard;
        testGrid.Tag = "2";
    }
    else
    {
        anim = testGrid.Resources["FadeAnim2to1"] as Storyboard;
        testGrid.Tag = "1";
    }
    anim.Begin();
}

【讨论】:

  • 谢谢。正如我所说,我可能会使用原生动画。仍然困扰着我,我无法采用自己的开发方法(无论多么被误导)而不遇到像这样荒谬的事情。
  • 嗯,线程是相当复杂的,你读过this article on MSDN吗?
  • 感谢您的链接。我想我只是老学校。我讨厌将我的应用程序的控制权交给一个愚蠢的 XML 伪代码 sn-p 的想法。我会读一读
  • 哇,不要侮辱我珍贵的XAML!
  • 我一直是喜欢控制而不是易用性的类型。不同的笔画配合
猜你喜欢
  • 2011-04-30
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-12
  • 2016-01-03
  • 1970-01-01
相关资源
最近更新 更多