Я пытался совместить c размытие acryli c приложения UWP с моим приложением WPF. Я уже пробовал использовать DWM Blur, но он не такой размытый, как Acryli c Bru sh в UWP, а также пробовал использовать setWindowCompositionAttribute (), который в настоящее время отстает от всего моего окна.
Недавно я видел код на github на Windows .UI.Composition-Win32-Samples
Они добились эффекта размытия Acryli c в WPF с использованием взаимодействия Win2D. но проблема в том, что они фактически создают другое окно и размещают его в исходное окно, поскольку пользовательский элемент управления, который сильно мерцает при изменении размера.
есть ли способ реализовать его непосредственно в окне WPF без использования хоста HWND.
Ссылка на проект Github
WPF Acryli c Эффект размытия с использованием Win2D Interop
Это код, который они используют:
CompositionHostControl.xaml.cs
sealed partial class CompositionHostControl : UserControl, IDisposable
{
private readonly CanvasDevice _canvasDevice;
private readonly IGraphicsEffect _acrylicEffect;
private readonly CompositionHost _compositionHost;
private readonly Compositor _compositor;
private readonly ContainerVisual _containerVisual;
private static double _rectWidth;
private static double _rectHeight;
private static bool _isAcrylicVisible = false;
private static SpriteVisual _acrylicVisual;
private static DpiScale _currentDpi;
private static CompositionGraphicsDevice _compositionGraphicsDevice;
private static CompositionSurfaceBrush _noiseSurfaceBrush;
public CompositionHostControl()
{
InitializeComponent();
// Get graphics device.
_canvasDevice = CanvasDevice.GetSharedDevice();
// Create host and attach root container for hosted tree.
_compositionHost = new CompositionHost();
CompositionHostElement.Child = _compositionHost;
_compositionHost.RegisterForDispose(this);
_compositor = _compositionHost.Compositor;
_containerVisual = _compositor.CreateContainerVisual();
// Create effect graph.
_acrylicEffect = CreateAcrylicEffectGraph();
}
private void CompositionHostControl_Loaded(object sender, RoutedEventArgs e)
{
_currentDpi = WindowsMedia.VisualTreeHelper.GetDpi(this);
_rectWidth = CompositionHostElement.ActualWidth / 2;
_rectHeight = CompositionHostElement.ActualHeight / 2;
// Get graphics device.
_compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(_compositor, _canvasDevice);
// Create surface.
var noiseDrawingSurface = _compositionGraphicsDevice.CreateDrawingSurface(
new Windows.Foundation.Size(_rectWidth, _rectHeight),
DirectXPixelFormat.B8G8R8A8UIntNormalized,
DirectXAlphaMode.Premultiplied);
// Draw to surface and create surface brush.
var noiseFilePath = AppDomain.CurrentDomain.BaseDirectory + "Assets\\NoiseAsset_256X256.png";
LoadSurface(noiseDrawingSurface, noiseFilePath);
_noiseSurfaceBrush = _compositor.CreateSurfaceBrush(noiseDrawingSurface);
// Add composition content to tree.
_compositionHost.SetChild(_containerVisual);
AddCompositionContent();
}
protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi)
{
base.OnDpiChanged(oldDpi, newDpi);
_currentDpi = newDpi;
Vector3 newScale = new Vector3((float)newDpi.DpiScaleX, (float)newDpi.DpiScaleY, 1);
// Adjust each child visual scale and offset.
foreach (SpriteVisual child in _containerVisual.Children)
{
child.Scale = newScale;
var newOffsetX = child.Offset.X * ((float)newDpi.DpiScaleX / (float)oldDpi.DpiScaleX);
var newOffsetY = child.Offset.Y * ((float)newDpi.DpiScaleY / (float)oldDpi.DpiScaleY);
child.Offset = new Vector3(newOffsetX, newOffsetY, 0);
}
}
public void AddCompositionContent()
{
var acrylicVisualOffset = new Vector3(
(float)(_rectWidth * _currentDpi.DpiScaleX) / 2,
(float)(_rectHeight * _currentDpi.DpiScaleY) / 2,
0);
// Create visual and set brush.
_acrylicVisual = CreateCompositionVisual(acrylicVisualOffset);
_acrylicVisual.Brush = CreateAcrylicEffectBrush();
}
SpriteVisual CreateCompositionVisual(Vector3 offset)
{
var visual = _compositor.CreateSpriteVisual();
visual.Size = new Vector2((float)_rectWidth, (float)_rectHeight);
visual.Scale = new Vector3((float)_currentDpi.DpiScaleX, (float)_currentDpi.DpiScaleY, 1);
visual.Offset = offset;
return visual;
}
async void LoadSurface(CompositionDrawingSurface surface, string path)
{
// Load from stream.
var storageFile = await StorageFile.GetFileFromPathAsync(path);
var stream = await storageFile.OpenAsync(FileAccessMode.Read);
var bitmap = await CanvasBitmap.LoadAsync(_canvasDevice, stream);
// Draw to surface.
using (var ds = CanvasComposition.CreateDrawingSession(surface))
{
ds.Clear(Colors.Transparent);
var rect = new Windows.Foundation.Rect(0, 0, _rectWidth, _rectHeight);
ds.DrawImage(bitmap, 0, 0, rect);
}
stream.Dispose();
bitmap.Dispose();
}
IGraphicsEffect CreateAcrylicEffectGraph()
{
return new BlendEffect
{
Mode = BlendEffectMode.Overlay,
Background = new CompositeEffect
{
Mode = CanvasComposite.SourceOver,
Sources =
{
new BlendEffect
{
Mode = BlendEffectMode.Exclusion,
Background = new SaturationEffect
{
Saturation = 2,
Source = new GaussianBlurEffect
{
Source = new CompositionEffectSourceParameter("Backdrop"),
BorderMode = EffectBorderMode.Hard,
BlurAmount = 30
},
},
Foreground = new ColorSourceEffect()
{
Color = Color.FromArgb(26, 255, 255, 255)
}
},
new ColorSourceEffect
{
Color = Color.FromArgb(153, 255, 255, 255)
}
}
},
Foreground = new OpacityEffect
{
Opacity = 0.03f,
Source = new BorderEffect()
{
ExtendX = CanvasEdgeBehavior.Wrap,
ExtendY = CanvasEdgeBehavior.Wrap,
Source = new CompositionEffectSourceParameter("Noise")
},
},
};
}
CompositionEffectBrush CreateAcrylicEffectBrush()
{
// Compile the effect.
var effectFactory = _compositor.CreateEffectFactory(_acrylicEffect);
// Create Brush.
var acrylicEffectBrush = effectFactory.CreateBrush();
// Set sources.
var destinationBrush = _compositor.CreateBackdropBrush();
acrylicEffectBrush.SetSourceParameter("Backdrop", destinationBrush);
acrylicEffectBrush.SetSourceParameter("Noise", _noiseSurfaceBrush);
return acrylicEffectBrush;
}
public void Dispose()
{
_acrylicVisual.Dispose();
_noiseSurfaceBrush.Dispose();
_canvasDevice.Dispose();
_compositionGraphicsDevice.Dispose();
}
internal void ToggleAcrylic()
{
// Toggle visibility of acrylic visual by adding or removing from tree.
if (_isAcrylicVisible)
{
_containerVisual.Children.Remove(_acrylicVisual);
}
else
{
_containerVisual.Children.InsertAtTop(_acrylicVisual);
}
_isAcrylicVisible = !_isAcrylicVisible;
}
}
CompositionHost.cs
sealed class CompositionHost : HwndHost
{
private readonly object _dispatcherQueue;
private readonly List<IDisposable> _registeredDisposables = new List<IDisposable>();
private readonly ICompositorDesktopInterop _compositorDesktopInterop;
private ICompositionTarget _compositionTarget;
public IntPtr HwndHost { get; private set; }
public Compositor Compositor { get; private set; }
public CompositionHost()
{
// Create dispatcher queue.
_dispatcherQueue = InitializeCoreDispatcher();
Compositor = new Compositor();
_compositorDesktopInterop = (ICompositorDesktopInterop)(object)Compositor;
}
public void SetChild(Visual v)
{
_compositionTarget.Root = v;
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
// Create Window
HwndHost = IntPtr.Zero;
HwndHost = User32.CreateWindowExW(
dwExStyle: User32.WS_EX.WS_EX_TRANSPARENT,
lpClassName: "Message",
lpWindowName: "CompositionHost",
dwStyle: User32.WS.WS_CHILD,
x: 0, y: 0,
nWidth: 0, nHeight: 0,
hWndParent: hwndParent.Handle,
hMenu: IntPtr.Zero,
hInstance: IntPtr.Zero,
lpParam: IntPtr.Zero);
// Get compositor and target for hwnd.
_compositorDesktopInterop.CreateDesktopWindowTarget(HwndHost, true, out _compositionTarget);
return new HandleRef(this, HwndHost);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
if (_compositionTarget.Root != null)
{
_compositionTarget.Root.Dispose();
}
User32.DestroyWindow(hwnd.Handle);
foreach (var d in _registeredDisposables)
{
d.Dispose();
}
}
// Register a given IDisposable object for disposal during cleanup.
public void RegisterForDispose(IDisposable d)
{
_registeredDisposables.Add(d);
}
private object InitializeCoreDispatcher()
{
DispatcherQueueOptions options = new DispatcherQueueOptions
{
apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA,
threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT,
dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions))
};
var hresult = CreateDispatcherQueueController(options, out object queue);
if (hresult != 0)
{
Marshal.ThrowExceptionForHR(hresult);
}
return queue;
}
internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
{
DQTAT_COM_NONE = 0,
DQTAT_COM_ASTA = 1,
DQTAT_COM_STA = 2
};
internal enum DISPATCHERQUEUE_THREAD_TYPE
{
DQTYPE_THREAD_DEDICATED = 1,
DQTYPE_THREAD_CURRENT = 2,
};
[StructLayout(LayoutKind.Sequential)]
internal struct DispatcherQueueOptions
{
public int dwSize;
[MarshalAs(UnmanagedType.I4)]
public DISPATCHERQUEUE_THREAD_TYPE threadType;
[MarshalAs(UnmanagedType.I4)]
public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
};
[DllImport("coremessaging.dll")]
internal static extern int CreateDispatcherQueueController(DispatcherQueueOptions options,
[MarshalAs(UnmanagedType.IUnknown)]
out object dispatcherQueueController);
}
[ComImport]
[Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICompositorDesktopInterop
{
void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out ICompositionTarget target);
}
[ComImport]
[Guid("A1BEA8BA-D726-4663-8129-6B5E7927FFA6")]
[InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
public interface ICompositionTarget
{
Visual Root
{
get;
set;
}
}