代码之家  ›  专栏  ›  技术社区  ›  Sivvy

创建非活动c_wpf窗口的缩略图

  •  7
  • Sivvy  · 技术社区  · 14 年前

    我在这里浏览了许多主题,并在谷歌上搜索信息,但我没有找到任何与我的问题有关的信息。

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

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

    也。。。有人能给我指出一些资源的方向吗?这些资源将帮助我找出如何在图像框中“最小化”动画?

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

    最后,我不确定这其中包含了什么,所以我不知道要为这篇文章添加什么标签。我会添加标签,以便其他人可以找到这些信息。

    编辑: 对不起,这是WPF。不知道会有什么不同。我在水渍险方面还没有特别的经验。

    3 回复  |  直到 14 年前
        1
  •  6
  •   hkon    14 年前

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

     <DockPanel>
            <StackPanel x:Name="myRect" >
                <TextBox Text="MyTexasdfasdfasdfasdfasdft" Height="50" />
                <CheckBox IsChecked="True"  />
                <Rectangle Fill="Red" Width="100" Height="100" />
            </StackPanel>
    
    
            <Button>
                <Button.Background>
                    <VisualBrush TileMode="None"  Viewport="0,0,1,1" Visual="{Binding ElementName=myRect}" >
                        <VisualBrush.Transform>
                            <ScaleTransform ScaleX="0.3" ScaleY="0.3" />
                        </VisualBrush.Transform>
                    </VisualBrush>
                </Button.Background>
            </Button>
        </DockPanel>
    

    编辑:虽然这个解决方案可以复制屏幕上的内容,但是当屏幕上的内容被隐藏或删除时,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;
    
        2
  •  3
  •   Ray Burns    14 年前

    我假设您需要实际的独立窗口,可以在屏幕周围和其他应用程序的窗口之间独立地拖动和放置。(如果这个假设是错误的,并且类似MDI的接口更适合您,请看Rob的答案。)

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

    1. 当isexpanded=false时,它使用ContentPresenter显示窗口内容本身,但是
    2. 当isexpanded=true时,它允许窗口显示自己的内容,但使用带有矩形的VisualBrush来显示该内容。

    它可能被命名为“WindowExpander”,并将其内容属性设置为展开展开时要显示的实际窗口对象。例如,它可以通过以下方式之一使用,具体取决于如何定义窗口:

    <UniformGrid Rows="2" Columns="2">
      <local:WindowExpander Window="{StaticResource Form1Window}" />
      <local:WindowExpander Window="{StaticResource Form2Window}" />
      <local:WindowExpander Window="{StaticResource Form3Window}" />
      <local:WindowExpander Window="{StaticResource Form4Window}" />
    </UniformGrid>
    
    <UniformGrid Rows="2" Columns="2">
      <local:WindowExpander><Window Width="800" Height="600"><local:Form1 /></Window></local:WindowExpander>
      <local:WindowExpander><Window Width="800" Height="600"><local:Form2 /></Window></local:WindowExpander>
      <local:WindowExpander><Window Width="800" Height="600"><local:Form3 /></Window></local:WindowExpander>
      <local:WindowExpander><Window Width="800" Height="600"><local:Form4 /></Window></local:WindowExpander>
    </UniformGrid>
    
    <ItemsControl ItemsSource="{Binding Forms}">
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate><UniformGrid Rows="2" Columns="2"/></ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
    </ItemsControl>
    

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

    <Style TargetType="local:WindowExpander">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="local:WindowExpander">
            <ToggleButton IsChecked="{TemplateBinding IsExpanded}">
              <Viewbox IsHitTestVisible="False">
                <ContentPresenter Content="{Binding Header} />
              </Viewbox>
            </ToggleButton>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    

    我想您可能希望实现类似以下的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控制窗口的可见性,但当isexpanded更改时,故事板会临时强制窗口在动画运行期间保持足够长的可见时间。在任何给定的时刻,模板中的窗口或ContentPresenter都包含窗口的内容。您可能会说,每当扩展器没有展开(没有窗口)时,内容都会从窗口“被盗”,以便在窗口扩展器中使用。这是通过swapContent方法完成的。它将用VisualBrush绘制的矩形放入窗口,并将窗口的实际内容放入头中,这是ToggleButton上显示的缩略图。

    这项技术解决了这样一个事实:VisualBrush不适用于不可见的可视对象,因为“内容”可视对象实际上总是可见的——它始终是窗口的子对象,或是视盒内ContentPresenter的子对象。

    因为使用了VisualBrush,缩略图总是提供实时预览。

    警告:不要在窗口级别设置DataContext或创建资源。如果你这样做了,当你的内容被“窃取”时,它将没有正确的数据上下文或资源,因此看起来不正确。我的建议是对每个表单使用一个用户控件而不是一个窗口,并让主表单将其包装在一个窗口中,如下图所示:

    <UniformGrid Rows="2" Columns="2">
      <local:WindowExpander><Window Width="800" Height="600"><local:Form1 /></Window></local:WindowExpander>
      <local:WindowExpander><Window Width="800" Height="600"><local:Form2 /></Window></local:WindowExpander>
      <local:WindowExpander><Window Width="800" Height="600"><local:Form3 /></Window></local:WindowExpander>
      <local:WindowExpander><Window Width="800" Height="600"><local:Form4 /></Window></local:WindowExpander>
    </UniformGrid>
    
        3
  •  1
  •   Rob Perkins    14 年前

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

    在较高的层次上,我想您可以通过将四个“表单”中的每一个定义为用户控件或内容演示者来实现这一点,也许在它们周围有一个边界。

    然后,当“表单”处于非活动状态时,使用 LayoutTransform RenderTransform 属性和其他定位属性一起定位和收缩它。一旦你的大脑习惯了混合,用“状态”和“触发器”来定义它就相当容易了。

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

    我发现“5天内学习融合”视频对此很有用,但我承认分享你的困惑;我发现没有一个统一的地方可以系统地教授XAML和WPF,而无需简单地参加第三方培训班或召集导师顾问。在这个时候,培训的第五天是“即将到来”,或者整个事情的关键是Silverlight而不是WPF,这都没有帮助。

    但是,这是一个开始,“学习混合”视频可以在这里找到:

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

    你还会看到一个链接,指向一个名为“工具箱”的东西,我还没有尝试过。