簡體   English   中英

創建非活動C#WPF窗口的縮略圖

[英]Create a thumbnail of an inactive C# WPF Window

我在這里查看了很多主題,並搜索了相關信息,但我沒有找到與我的問題有關的任何內容。

我想要做的就是讓用戶啟動應用程序時,主窗口(不是MDI)打開時有四個圖像框,每個圖像框顯示一個窗體的圖像,當它們點擊它時會打開。 一旦選定的表單打開並進行了更改,如果他們單擊以最小化/關閉表單,它將(看似)最小化到圖像框中,顯示表單在縮略圖視圖中的外觀的實時圖像。

我的問題是,如何將圖像制作成圖像,以便將圖像用作圖像框中的縮略圖?

此外......有人能指出我的某些資源,這將有助於我弄清楚如何動畫“最小化”到圖像框?

我不是要求任何人為我做我的工作,因為我想自己學習,但我有點卡住了。

最后,我不確定這涉及到什么,所以我不知道為這篇文章添加什么標簽。 當我弄清楚時,我會添加標簽,以便其他人可以找到這些信息。

編輯:對不起,它在WPF中。 不確定它會有什么不同。 我在WPF方面仍然沒有特別的經驗。

您可以使用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;

我假設您想要實際單獨的窗口,可以在其他應用程序的窗口中獨立地在屏幕上拖放。 (如果這個假設不正確並且類似MDI的界面對你更好,請看看Rob的回答。)

我將實現一個接受Window的Expander子類,並且:

  1. 當IsExpanded = false時,它使用ContentPresenter呈現窗口內容,但是
  2. 當IsExpanded = true時,它會讓窗口顯示自己的內容,但使用帶有Rectangle的VisualBrush來顯示該內容

它可能被命名為“WindowExpander”,並且將其Content屬性設置為擴展Expander時要顯示的實際Window對象。 例如,它可以以下列方式之一使用,具體取決於Windows的定義方式:

<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,其中包含一個顯示縮略圖的ViewBox,如下所示:

<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控制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中,如下所示:

<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>

如果您是從WPF開始,那么您計划要做的事情可能要求您學習混合以定義條件和動畫,或者深入了解動畫系統以便理解它並手動編碼XAML。

在高層次上,我想你可以通過將你的四個“形式”中的每一個定義為UserControls或ContentPresenters來實現這一點,也許是圍繞它們的邊框。

然后,當“表單”處於非活動狀態時,使用LayoutTransformRenderTransform屬性以及其他定位屬性來定位和縮小它。 一旦你的大腦習慣於混合,實際上很容易使用“狀態”和“觸發器”來定義它。

要添加行為以增長最小化的表單,請處理“PreviewMouseDown”事件,並在處理程序中測試表單的狀態。

我發現“5天學習混合”視頻對此有用,但我承認分享你的困惑; 我發現沒有統一的地方以系統的方式教授XAML和WPF,而不是簡單地參加第三方培訓課程或打電話給導師顧問。 在這個時候,培訓的第五天是“即將推出”,或者整個事情都是關鍵的Silverlight而不是WPF,這沒有任何幫助。

但是,這是一個開始; “學習混合”視頻可在此處找到:

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

你還會看到一個名為“.toolbox”的鏈接,我還沒有嘗試過。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM