![](/img/trans.png)
[英]How to force the refresh of the thumbnail when the window is minimized ? (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子類,並且:
它可能被命名為“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來實現這一點,也許是圍繞它們的邊框。
然后,當“表單”處於非活動狀態時,使用LayoutTransform
或RenderTransform
屬性以及其他定位屬性來定位和縮小它。 一旦你的大腦習慣於混合,實際上很容易使用“狀態”和“觸發器”來定義它。
要添加行為以增長最小化的表單,請處理“PreviewMouseDown”事件,並在處理程序中測試表單的狀態。
我發現“5天學習混合”視頻對此有用,但我承認分享你的困惑; 我發現沒有統一的地方以系統的方式教授XAML和WPF,而不是簡單地參加第三方培訓課程或打電話給導師顧問。 在這個時候,培訓的第五天是“即將推出”,或者整個事情都是關鍵的Silverlight而不是WPF,這沒有任何幫助。
但是,這是一個開始; “學習混合”視頻可在此處找到:
http://www.microsoft.com/expression/resources/blendtraining/
你還會看到一個名為“.toolbox”的鏈接,我還沒有嘗試過。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.