【问题标题】:Changing Opacity With Reactive Extensions使用响应式扩展改变不透明度
【发布时间】:2015-11-13 03:43:29
【问题描述】:

是的,我知道这在 WPF 中会更容易实现。我经常听到。可悲的是,这是不可能的。

我正在编写一个 WinForms 应用程序,我需要“淡入”和“淡出”一个控件。透明度在 WinForms 中几乎是不可能的,所以我尝试使用不透明度:这个想法是在一段时间内更改每个子控件的 ForeColor 属性的 Alpha 通道。这似乎是处理我的 Reactive Extensions 的最佳时机!

我可能的解决方案是:

private void FadeOut()
{
   // our list of values for the alpha channel (255 to 0)
   var range = Enumerable.Range(0,256).Reverse().ToList();

   // how long between each setting of the alpha (huge value for example only)
   var delay = Timespan.FromSeconds(0.5);

   // our "trigger" sequence, every half second
   Observable.Interval(delay)
        // paired with the values from the range - we just keep the range
          .Zip(range, (lhs, rhs) => rhs)
        // make OnNext changes on the UI thread
          .ObserveOn(SynchronizationContext.Current)
        // do this every time a value is rec'd from the sequence
          .Subscribe(
              // set the alpha value
              onNext:ChangeAlphaValues, 
              // when we're done, really hide the control
              onCompleted: () => Visible = false, 
              // good citizenry
              onError: FailGracefully);
}

// no need to iterate the controls more than once - store them here
private IEnumerable<Control> _controls;

private void ChangeAlphaValues(int alpha)
{
    // get all the controls (via an extension method)
    var controls = _controls ?? this.GetAllChildControls(typeof (Control));

    // iterate all controls and change the alpha
    foreach (var control in controls)
       control.ForeColor = Color.FromArgb(alpha, control.ForeColor);
}

...这看起来令人印象深刻,但它不起作用。真正令人印象深刻的部分是它不能以两种方式工作!如果我继续这样做,我的下一次绩效评估将获得“远超”。 :-)

  1. (实际上并不是问题的 Rx 部分)alpha 值实际上似乎没有任何区别。尽管设置了这些值,但显示看起来是一样的。
  2. 如果我在序列完成之前关闭窗口,我会收到以下错误:

System.InvalidOperationException 未处理 消息:System.Reactive.Core.dll 中出现“System.InvalidOperationException”类型的未处理异常 附加信息:在创建窗口句柄之前,不能对控件调用 Invoke 或 BeginInvoke。

我认为这是取消令牌派上用场的地方 - 但我不知道如何实现它。

我需要以下方面的指导:

如果序列仍在运行,如何优雅地关闭窗口(即不抛出错误),以及如何让颜色的 alpha 值在更改后真正显示

...或者这可能是完全错误的方法。

我愿意接受其他建议。

【问题讨论】:

  • I am writing a WinForms app, and I need to "fade" a Control in &amp; out - 使用 WPF。 winforms 不支持动画。您可以在 WPF 中使用一行 XAML 实现此目的。
  • Sadly, It is not possible - 然后忘记尝试在 winforms 上引入动画或任何其他丰富的 UI 功能。花时间创建战舰灰色、无聊的 UI,这就是 winforms 的意义所在。
  • 所以,您还没有完全接受其他建议。 ;) 我很好奇为什么这是不可能的。您可以使用ElementHost 将 WPF 控件放入 WinForms。这对你来说可能吗?
  • 你试过检查Control.IsHandleCreated &amp;&amp; ! Control.IsDisposed吗?
  • @HighCore which is what winforms is about ... 叹息。是的,我知道。别再戳熊了。 ;-)

标签: c# winforms system.reactive opacity


【解决方案1】:

在 WinForms 透明度部分,我无法为您提供帮助。也许你应该把问题一分为二。

但对于 Rx 部分,您只需要在窗口关闭时取消订阅即可。 Subscribe 返回 IDisposable。您应该在 Closed 事件中处理它。

而且,由于我假设这个淡入淡出动画可能会在窗口关闭之前被多次调用,所以我们可以使用 Rx 助手 SerialDisposable

最后,Interval 实际上返回了一个计数。我们可以通过计算所需的 alpha 来使用它来简化您的 observable。

private SerialDisposable _fadeAnimation = new SerialDisposable();

private void FadeOut()
{
    // how long between each setting of the alpha (huge value for example only)
    var delay = Timespan.FromSeconds(0.5);

    _fadeAnimation.Disposable = Observable
        .Interval(delay)
        // 256 animation steps
        .Take(256)
        // calculate alpha
        .Select(i => 255 - i)
        .ObserveOn(SynchronizationContext.Current)
        .Subscribe(
            // set the alpha value
            onNext:ChangeAlphaValues, 
            // when we're done, really hide the control
            onCompleted: () => Visible = false, 
            // good citizenry
            onError: FailGracefully);
}

private void Form1_Closed()
{
    _fadeAnimation.Dispose();
}

【讨论】:

  • 你搞定了 Rx 部分。我必须为Dispose 事件创建一个EventHandler(因为它是一个控件,而不是一个表单)并将_fadeAnimation.Dispose() 放在那里 - 但是苹果/苹果。谢谢。
  • 在这种情况下SerialDisposable 会不会更好?如果在第一个订阅完成之前再次触发FadeOut,则不会释放第一个订阅。
  • 作为一个建议,我会使用 Observable.Generate(255, x =&gt; x &gt;= 0, x =&gt; x - 1, x =&gt; x, x =&gt; TimeSpan.FromSeconds(0.5)) 作为你的基本 observable。
  • @paulpdaniels 是的,你是对的。我认为这就是 MultipleAssignmentDisposable 所做的,但我猜不是。
猜你喜欢
  • 1970-01-01
  • 2011-09-10
  • 2012-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
相关资源
最近更新 更多