创建非活动C#WPF窗口的缩略图

我在这里查看了很多主题,并搜索了相关信息,但我没有找到与我的问题有关的任何内容。

我想要做的是,当用户启动应用程序时,主窗口(不是MDI)打开时有四个图像框,每个图像框显示一个窗体的图像,当它们点击它时会打开。 一旦打开所选表单并进行更改,如果他们单击以最小化/关闭表单,它(似乎)将最小化到图像框中,显示在缩略图视图中表单的实时图像。

我的问题是,如何将表单制作成图像,以便将图像用作图像框中的缩略图?

还有…有人能指出我的某些资源,这将有助于我弄清楚如何动画“最小化”到图像框?

我不是要求任何人为我做我的工作,因为我想自己学习,但我有点卡住了。

最后,我不确定这涉及到什么,所以我不知道要为这篇文章添加什么标签。 当我弄清楚时,我会添加标签,以便其他人可以找到这些信息。

编辑:对不起,它在WPF中。 不确定它会有什么不同。 我在WPF方面仍然没有特别的经验。

您可以使用VisualBrush,这是一个按钮的快速示例,其背景设置为stackpanel的缩小版本。

        

编辑:虽然这个解决方案可以复制屏幕上的内容,当隐藏或删除屏幕上的内容时,VisualBrush也是如此。 为了保持图像,有必要将控件呈现为位图。 这可以使用RenderTargetBitMap完成

 // CenterControl is the target to render, ShowControl is the control to render the CenterControl onto. var rtb = new RenderTargetBitmap((int)CenterControl.ActualWidth, (int)CenterControl.ActualHeight, 96, 96, PixelFormats.Pbgra32); rtb.Render(CenterControl); var bgBrush = new ImageBrush(rtb) {Transform = new ScaleTransform(0.1, 0.1)}; ShowControl.Background = bgBrush; 

我假设您需要实际单独的窗口,可以在其他应用程序的窗口中独立地在屏幕上拖放。 (如果这个假设不正确并且类似MDI的界面对你更好,请看看Rob的回答。)

我将实现一个接受Window的Expander子类,并且:

  1. 当IsExpanded = false时,它使用ContentPresenter呈现窗口内容,但是
  2. 当IsExpanded = true时,它会让窗口显示自己的内容,但使用带有Rectangle的VisualBrush来显示该内容

它可能被命名为“WindowExpander”,并且将其Content属性设置为扩展Expander时要显示的实际Window对象。 例如,它可以以下列方式之一使用,具体取决于Windows的定义方式:

                  

WindowExpander的实现将是一个ToggleButton,其中包含一个显示缩略图的ViewBox,如下所示:

  

我想你可能想要实现像这样的WindowExpander:

 [ContentProperty("Window")] public class WindowExpander : Expander { Storyboard _storyboard; public static WindowExpander() { DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowExpander), new FrameworkPropertyMetadata(typeof(WindowExpander))); IsExpandedProperty.OverrideMetadata(typeof(WindowExpander), new FrameworkPropertyMetadata { PropertyChangedCallback = (obj, e) => { var expander = (WindowExpander)obj; if(expander.Window!=null) { expander.SwapContent(expander.Window); expander.AnimateWindow(); } } }); } public Window Window { get { return (Window)GetValue(WindowProperty); } set { SetValue(WindowProperty, value); } } public static readonly DependencyProperty WindowProperty = DependencyProperty.Register("Window", typeof(Window), typeof(WindowExpander), new UIPropertyMetadata { PropertyChangedCallback = (obj, e) => { var expander = (WindowExpander)obj; var oldWindow = (Window)e.OldValue; var newWindow = (Window)e.NewValue; if(oldWindow!=null) { if(!expander.IsExpanded) expander.SwapContent(oldWindow); oldWindow.StateChanged -= expander.OnStateChanged; } expander.ConstructLiveThumbnail(); if(newWindow!=null) { if(!expander.IsExpanded) expander.SwapContent(newWindow); newWindow.StateChanged -= expander.OnStateChanged; } } }); private void ConstructLiveThumbnail() { if(Window==null) Header = null; else { var rectangle = new Rectangle { Fill = new VisualBrush { Visual = (Visual)Window.Content } }; rectangle.SetBinding(Rectangle.WidthProperty, new Binding("Width") { Source = Window }); rectangle.SetBinding(Rectangle.HeightProperty, new Binding("Height") { Source = Window }); Header = rectangle; } } private void SwapContent(Window window) { var a = Header; var b = window.Content; Header = null; window.Content = null; Header = b; window.Content = a; } private void AnimateWindow() { if(_storyboard!=null) _storyboard.Stop(Window); var myUpperLeft = PointToScreen(new Point(0, 0)); var myLowerRight = PointToScreen(new Point(ActualWidth, ActualHeight)); var myRect = new Rect(myUpperLeft, myLowerRight); var winRect = new Rect(Window.Left, Window.Top, Window.Width, Window.Height); var fromRect = IsExpanded ? myRect : winRect; // Rect where the window will animate from var toRect = IsExpanded ? winRect : myRect; // Rect where the window will animate to _storyboard = new Storyboard { FillBehavior = FillBehavior.Stop }; // ... code to build storyboard here ... // ... should animate "Top", "Left", "Width" and "Height" of window from 'fromRect' to 'toRect' using desired timeframe // ... should also animate Visibility=Visibility.Visible at time=0 _storyboard.Begin(Window); Window.Visibility = IsExpanded ? Visibility.Visible : Visibility.Hidden; } private void OnStateChanged(object sender, EventArgs e) { if(IsExpanded && Window.WindowState == WindowState.Minimized) { Window.WindowState = WindowState.Normal; IsExpanded = false; } } } 

上面的代码省略了构造动画的步骤。 它还没有经过测试 – 它只是快速地写在我的头顶。 我希望这个对你有用。

工作原理:IsExpanded控制Window的可见性,但IsExpanded更改故事板时会暂时强制窗口保持足够长的时间以便动画运行。 在任何给定时刻,模板中的Window或ContentPresenter都包含窗口的内容。 您可能会说,无论何时扩展器未展开(无窗口),内容都会从窗口“被盗”,以便在WindowExpander中使用。 这是通过SwapContent方法完成的。 它将使用VisualBrush绘制的Rectangle放入Window,将Window的实际内容放入Header,这是ToggleButton上显示的缩略图。

这种技术解决了VisualBrush无法在不可见的Visual上工作的事实,因为“Content”视觉实际上始终是可见的 – 它始终是ViewBox中的Window或ContentPresenter的子节点。

由于使用了VisualBrush,因此缩略图始终提供实时预览。

需要注意的是:不要在Window级别设置DataContext或创建资源。 如果您这样做,当您的内容被“窃取”时,它将没有正确的DataContext或资源,因此它看起来不正确。 我的建议是为每个表单使用UserControl而不是Window,并让您的主表单将其包装在Window中,如下所示:

       

如果您从WPF开始,那么您计划要做的事情可能需要您学习混合以定义条件和动画,或者深入了解动画系统以便理解它并手动编码XAML。

在高层次上,我想你可以通过将你的四个“forms”中的每一个定义为UserControls或ContentPresenters来实现这一点,也许是围绕它们的边框。

然后,当“表单”处于非活动状态时,使用LayoutTransformRenderTransform属性以及其他定位属性来定位和缩小它。 一旦你的大脑习惯了混合,实际上很容易使用“状态”和“触发器”来定义它。

要添加行为以增长最小化的表单,请处理“PreviewMouseDown”事件,并在处理程序中测试表单的状态。

我发现“5天学习混合”video对此有用,但我承认要分享你的困惑; 我发现没有统一的地方以系统的方式教授XAML和WPF,而不是简单地参加第三方培训课程或打电话给导师顾问。 在这个时候,培训的第五天是“即将推出”,或者整个事情都是关键的Silverlight而不是WPF,这没有任何帮助。

但是,这是一个开始; “学习混合”video可在此处找到:

http://www.microsoft.com/expression/resources/blendtraining/

你还会看到一个名为“.toolbox”的链接,我还没有尝试过。