使用反应式扩展更改不透明度

本文关键字:不透明度 扩展 反应式 | 更新日期: 2023-09-27 18:08:50

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

我正在编写一个WinForms应用程序,我需要"淡入"控件。 在 WinForms 中,透明度几乎是不可能的,因此我尝试使用不透明度:这个想法是在一段时间内更改每个子控件的 ForeColor 属性的 Alpha 通道。 这似乎是处理我的反应式扩展的最佳时机!

我可能的解决方案是:

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 is unhandling 消息:System.Reactive.Core 中发生类型为"System.InvalidOperationException"的未处理异常.dll 其他信息:在创建窗口句柄之前,无法在控件上调用调用 Invoke 或 BeginInvoke。

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

我需要以下方面的指导:

如果序列仍在运行,如何优雅地关闭窗口(即不引发错误(,以及如何获取颜色更改后实际显示的 alpha 值。

。或者也许这完全是错误的方法。

我愿意接受其他建议。

使用反应式扩展更改不透明度

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

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

而且,由于我假设在窗口关闭之前可能会多次调用此淡入淡出动画,因此我们可以使用 Rx 帮助程序SerialDisposable .

最后,Interval实际上返回一个计数。 我们可以使用它来简化您的可观察量,只需计算所需的 alpha。

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