我在这里查看了很多主题,并搜索了相关信息,但我没有找到与我的问题有关的任何内容。
我想要做的就是让用户启动应用程序时,主窗口(不是MDI)打开时有四个图像框,每个图像框显示一个图像,当它们点击它时会打开。打开选定的表单并进行更改后,如果他们单击以最小化/关闭表单,它将(看似)最小化到图像框中,显示表单在缩略图视图中的实时图像。
我的问题是,如何将图像制作成图像,以便将图像用作图像框中的缩略图?
此外......有人能指出一些资源的方向,这将有助于我弄清楚如何动画“最小化”到图像框中吗?
我不是要求任何人为我做我的工作,因为我想自己学习,但我有点卡住了。
最后,我不确定这涉及到什么,所以我不知道要为这篇文章添加什么标签。我会在我弄清楚时添加标签,以便其他人可以找到这些信息。
编辑:抱歉,它在WPF中。不确定它会有什么不同。我在WPF方面仍然没有特别的经验。
答案 0 :(得分:6)
您可以使用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;
答案 1 :(得分:3)
我将假设您需要实际单独的窗口,可以在其他应用程序的窗口中独立地在屏幕上拖放。 (如果这个假设不正确并且类似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>
答案 2 :(得分:1)
如果您刚开始使用WPF,那么您计划要做的事情可能需要您学习Blend以定义条件和动画,或者深入了解动画系统以便理解它和手 - 编码XAML。
在高层次上,我想你可以通过将你的四个“形式”中的每一个定义为UserControls或ContentPresenters来实现这一点,也许是围绕它们的边框。
然后,当“表单”处于非活动状态时,请使用LayoutTransform
或RenderTransform
属性以及其他定位属性来定位和缩小它。一旦你的大脑习惯于混合,实际上很容易使用“状态”和“触发器”来定义它。
要添加行为以增长最小化的表单,请处理“PreviewMouseDown”事件,并在处理程序中测试表单的状态。
我发现“5天学习混合”视频对此有用,但我承认分享你的困惑;我发现没有统一的地方以系统的方式教授XAML和WPF,而不是简单地参加第三方培训课程或打电话给导师顾问。在这个时候,培训的第五天是“即将推出”,或者整个事情都是关键的Silverlight而不是WPF,这没有任何帮助。
但是,这是一个开始; “学习混合”视频可在此处找到:
http://www.microsoft.com/expression/resources/blendtraining/
你还会看到一个名为“.toolbox”的链接,我还没有尝试过。