Create Thumbnail Inactive WPF Window C #

I looked through a lot of topics and searched for information, but did not find anything that related to my question.

What I want to do is when the user launches the application, the main window (and not MDI) opens with four image boxes, each of which shows an image of the form that will open when you click on it. After the selected form is opened and the changes are made, if they click to minimize / close the form, it (apparently) will disappear in the image window, displaying a real-time image of how the form looks in the form of thumbnails.

My question is: how do I make the shape in the image so that I can use the thumbnail image in the image window?

Also ... Can someone point me towards some resources that will help me figure out how to animate the "minimization" in the image window?

I do not ask anyone to do their work for me, because I would like to study it myself, but I'm a little stuck.

Finally, I’m not sure what is connected with this, so I don’t know what tags to put for this message. I will add tags as I find out so that others can find this information.

EDIT: Sorry, this is in WPF. I was not sure that it would be otherwise. I'm still not particularly good at WPF.

+6
c # wpf
source share
3 answers

You can use VisualBrush, here is a brief example of a button with a background set to a smaller version of the stack panel.

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

Edit: although this solution works to copy material that is on the screen when the material on the screen is hidden or deleted, just like VisualBrush. To save the image, you must display the control in a bitmap. This can be done using 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; 
+6
source share

I'm going to assume that you need actual individual windows that you can drag independently around the screen among other application windows. (If this assumption is incorrect and an MDI-like interface is better for you, take a look at Rob's answer.)

I would subclass Expander, which takes a window and:

  • When IsExpanded = false, it itself represents the contents of the window using ContentPresenter, but
  • When IsExpanded = true, it allows the window to present its own content, but uses a VisualBrush with a rectangle to display that content

It can be called "WindowExpander" and will have the Content property set for the actual Window object that will be displayed when the Expander extension is used. For example, it can be used in one of these ways, depending on how your Windows is detected:

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

The WindowExpander implementation will be a ToggleButton containing a ViewBox that displays a thumbnail, for example:

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

I think you probably want to implement WindowExpander something like this:

 [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; } } } 

There are no steps in the above code to create the animation. It was also not tested - it was simply written quickly from the head. Hope this works for you.

How it works: IsExpanded controls the visibility of the Window, except that when you change IsExpanded, the storyboard temporarily makes the window remain visible long enough to start the animation. At any given time, a Window or ContentPresenter in a template contains the contents of a window. You can say that whenever the expander does not expand (without a window), the Content is “stolen” from the window for use in WindowExpander. This is done by the SwapContent method. It puts the rectangle drawn with VisualBrush in the window and the actual contents of the window in the title bar, this is the thumbnail displayed in ToggleButton.

This method works around the fact that VisualBrush does not work with invisible Visuals because the Content visual is actually always visible - it is always a child of a Window or ContentPresenter inside the ViewBox.

Since VisualBrush is used, the thumbnail always gives a live preview.

One warning: do not set the DataContext or create resources at the window level. If you do this when your content is “stolen”, it will not have the required DataContext or resources, so it will not look right. My recommendation would be to use UserControl instead of Window for each form, and your main form will transfer it to Window, as shown here:

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

If you are starting out with WPF, then what you are planning to do is likely to require that you either study Blend to determine the conditions and animation, or dive deep into the animation system to understand it and to understand -encoding XAML.

At a high level, I think you could approach this by specifying each of the four “forms” as UserControls or ContentPresenters, possibly with a border around them.

Then, when the “shape” is inactive, use the LayoutTransform or RenderTransform along with other positioning properties to position and compress it. Once your brain is accustomed to Blend, it is actually quite easy to determine this using States and Triggers.

To add behavior to increase the minimized form, handle the PreviewMouseDown event and the handler, check the state of the form.

I found the video “Learn Blend in 5 Days” useful for this, but I admit to sharing your confusion; there is no single place that I found that teaches XAML and WPF in a systematic way, not just enrolling in a third-party classroom or inviting a mentor consultant. It doesn’t help at this time, the fifth day of training is “Coming Soon”, or that all this is related to Silverlight, and not to WPF.

But this is the beginning; The Learn Blend video can be found here:

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

You will also see a link to something called ".toolbox", which I have not tried yet.

+1
source share

All Articles