Krisztián's profileBátyai Krisztián[KRis]PhotosBlogListsMore ![]() | Help |
|
September 12 Rolling Menu
Találtam egy érdekes/designos menüt, amit egy kicsit átalakítottam, hogy bármilyen UI elemet tudjon fogadni, és azt egyszerűen meg lehessen adni, és design alatt látni hogy mit gyártunk... Átalakítás: <UserControl x:Class="SilverKatalogus.MenuImage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="90" d:DesignHeight="90" > <UserControl.Resources> <Storyboard x:Name="Storyboard1"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="content" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"> <SplineDoubleKeyFrame KeyTime="00:00:00.2000000" x:Name="MyKeyFrame" Value="-1"> <SplineDoubleKeyFrame.KeySpline> <KeySpline ControlPoint1="0,0" ControlPoint2="0.504000008106232,1"/> </SplineDoubleKeyFrame.KeySpline> </SplineDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> </Storyboard> </UserControl.Resources> <!-- don't remove the background, required for correct LeaveEvent--> <Grid x:Name="LayoutRoot" MouseEnter="Image_MouseEnter" MouseLeave="image_MouseLeave" Background="Transparent" Cursor="Hand" RenderTransformOrigin="0.5,0.5"> <ContentPresenter RenderTransformOrigin="0.5,0.5" x:Name="content"> <ContentPresenter.RenderTransform> <TransformGroup> <ScaleTransform /> </TransformGroup> </ContentPresenter.RenderTransform> </ContentPresenter> <!--<Image RenderTransformOrigin="0.5,0.5" x:Name="image"> <Image.RenderTransform> <TransformGroup> <ScaleTransform /> </TransformGroup> </Image.RenderTransform> </Image>--> <Grid.RenderTransform> <TransformGroup> <RotateTransform x:Name="MyAngle"/> </TransformGroup> </Grid.RenderTransform> </Grid> </UserControl> Látható, hogy egy kép helyett ContentPresenterben jelenítem meg a dolgokat... Ehhez 2 DependencyProperty-re van szükség, és ezt a UIElement-et jelenítem meg a 2 kép helyett (normal, rolled). (a kódban a dep propertyk a lényegek, csak a teljesség kedvéért tettem ide az egész osztályt...) public partial class MenuImage : UserControl { public MenuImage() { InitializeComponent(); Storyboard1.Completed += new EventHandler(Storyboard1_Completed); } private enum MyStates { Normal, Started1, Started2, Reverse1, Reverse2 }; private MyStates MyState = MyStates.Normal; public int Duration { get { return (int)GetValue(DurationProperty); } set { SetValue(DurationProperty, value);MyKeyFrame.KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, value)); } } // Using a DependencyProperty as the backing store for Duration. This enables animation, styling, binding, etc... public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof(int), typeof(MenuImage), null ); public int Angle { get { return (int)GetValue(AngleProperty); } set { SetValue(AngleProperty, value); MyAngle.Angle = value;} } // Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc... public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(int), typeof(MenuImage), null); public UIElement UINormal { get { return (UIElement)GetValue(UINormalProperty); } set { SetValue(UINormalProperty, value); content.Content = value; } } // Using a DependencyProperty as the backing store for UINormal. This enables animation, styling, binding, etc... public static readonly DependencyProperty UINormalProperty = DependencyProperty.Register("UINormal", typeof(UIElement), typeof(MenuImage), null); public UIElement UIRoll { get { return (UIElement)GetValue(UIRollProperty); } set { SetValue(UIRollProperty, value); } } // Using a DependencyProperty as the backing store for UIRoll. This enables animation, styling, binding, etc... public static readonly DependencyProperty UIRollProperty = DependencyProperty.Register("UIRoll", typeof(UIElement), typeof(MenuImage), null); private void Reverse2() { MyState = MyStates.Reverse2; //this.image.Source = _normalImage; content.Content = UINormal; MyKeyFrame.Value = 1; Storyboard1.Begin(); } private void Reverse1() { MyState = MyStates.Reverse1; MyKeyFrame.Value = 0; Storyboard1.Begin(); } private void Start1() { MyState = MyStates.Started1; MyKeyFrame.Value = 0; Storyboard1.Begin(); } private void Start2() { MyState = MyStates.Started2; //this.image.Source = _rollImage; content.Content = UIRoll; MyKeyFrame.Value = 1; Storyboard1.Begin(); } private void Image_MouseEnter(object sender, MouseEventArgs e) { Canvas.SetZIndex(this, Canvas.GetZIndex(this) + 4); switch (MyState) { case MyStates.Normal: case MyStates.Reverse2: Start1(); break; default: Start2(); break; } } private void image_MouseLeave(object sender, MouseEventArgs e) { Canvas.SetZIndex(this, Canvas.GetZIndex(this) - 4); switch (MyState) { case MyStates.Started2: Reverse1(); break; case MyStates.Started1: Reverse2(); break; } } void Storyboard1_Completed(object sender, EventArgs e) { switch (MyState) { case MyStates.Started1: Start2(); break; case MyStates.Reverse1: Reverse2(); break; case MyStates.Reverse2: MyState = MyStates.Normal; break; } } } Használat: <local:MenuImage Angle="10" Width="120" Height="120" Margin="10"> <local:MenuImage.UINormal> <Image Source="Images/users.png"></Image> </local:MenuImage.UINormal> <local:MenuImage.UIRoll> <Border BorderBrush="Gray" BorderThickness="2" CornerRadius="3" > <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10">Oktatók</TextBlock> </Border> </local:MenuImage.UIRoll> </local:MenuImage> És az eredmény : September 11 ScreenCast
Elkészült az első screencastom, első első és első Silverlight 2.0. Hogy is szokták mondani?!? Remélem hamarosan jön a többi is, egy értelmes tematika szerint... http://www.devportal.hu/groups/silverlight/blog/archive/2008/09/10/els-silverlight2-screencast.aspx WebMappa : http://files.devportal.hu/Demo/ -- September 10 XAML && Binding && Converter && IMultiValueConverter
Igen hasznos dolog WPF/SL-os XAML újdonság a Binding. Ügyesen használva minimális "erőfeszítéssel", értsd kódolással-hekkeléssel, egész komplex működést is el lehet érni. Milyen problémákba ütközhetünk?
Oldjuk fel a problémákat!! Source megadása
Ezzel gyakorlatilag mindent le lehet fedni, mindenkit meg lehet találni akinek a Property-jét fel akarjuk használni. Konverzió Erre a WPF-ben és SL-ban a konverterek állnak rendelkezésre: Gyári konverterek, pl:
Ez sok esetben kevés, sőt :) általában kevés. De sebaj, gyártani tudunk sajátot: public class MyConverter : IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } Mint látható kapunk egy értéket amit konvertálni kell, kapunk egy paramétert amit fel tudunk használni a konverzióhoz ( megkapjuk a cél type-t, és a culture-t). {Binding Converter="{StaticResource HeightConverter}"...} Paramétert a ConverterParameter="123"-al tudunk megadni a binding-ban. De.... mi van ha több paramétert akarok megadni, és bindolni szeretnék?!? Hát akkor nincs más hátra, mint az IMultiValueConverter:
public class HeightConverter : IMultiValueConverter { #region IMultiValueConverter Members public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double value = (double)values[0]; double height = (double)values[1]; double min= (double)values[2]; double max = (double)values[3]; return (height-min) * (double)value / (max-min)*0.8; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } Itt már nem csak egy értéket hanem bármennyit kaphatunk.... és a lényeg bárhonnan: <Rectangle x:Name="rectFill" Fill="DarkRed" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"> <Rectangle.Height> <MultiBinding Converter="{StaticResource HeightConverter}" > <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ActualHeight"/> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/> </MultiBinding> </Rectangle.Height> </Rectangle> Mint látható minden egyes paraméternek külön meg lehet adni a forrást (jelen példában ugyanaz...), így akár több helyről is össze tudjuk szedni szükséges értékeket... Jelen példában készítettem a progressbar-t, ami stílusosan egy sörösüveg :), ami megtellik... Source : http://beta.devportal.hu/groups/wpf/media/p/946.aspx September 03 Silverlight MDI Surface
WPF-ben tanulási időszakban készítettem egy Surface-t amire mindenféle elemeket lehetett dobálgatni, ott átméretezni, rendezgetni stb. Ezt WPF-ben könnyen meg lehet tenni egy Canvas és a Thumb segítségével.
De miért ne tennénk ezt meg Silverlight2-ben? És hívjuk az elemet Window-nak, legyen Title-je, és máris van egy Winforms MDI szerű rendszerünk! Lássuk! 1. MDI Window Mi sem egyszerűbb! Mindösszesen egy Canvas: <UserControl x:Class="SilverWindowEngine.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="800" Height="600"> <Grid x:Name="LayoutRoot" Background="White"> <Canvas x:Name="canvasMDI"> </Canvas> </Grid> </UserControl> Természetesen, ha szeretnénk olyan funkciókat, hogy rendezés ( Cascade,Tile,stb), vagy Window listát, akkor azt itt implementálni kell. 2. Szükségünk van egy Window control-ra, ami tud működni egy MDI felületen, azaz egy Canvas-on. Készítsünk egy UserControl-t : SilverWindow
Ehhez alakítsuk ki a felületünket: <Grid.RowDefinitions> Cím: <StackPanel Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center"> <TextBlock>Title</TextBlock> </StackPanel> Mozgatás: <Rectanglex:Name="rectDrag"MouseLeftButtonDown="rectDrag_MouseLeftButtonDown" Bezárás: <Button x:Name="btnClose" Content="X" Grid.Column="1" Grid.Row="0" Tartalom: <Grid x:Name="grdContentPresenter" Grid.Row="1" Grid.ColumnSpan="2"> </Grid> Ebbe a gridbe fogjuk betenni az ablak tartalmát! Méretezés: <Rectangle x:Name="rectResizeWidth" A megfelelő paraméterek beállításával a két szélén az ablaknak érzékeny lesz a 2 Rectangle, ha megfelelően írjuk meg az eseményvezérlőket, akkor pont azt fogják csinálni amit szeretnénk! Díszítés: <Border BorderThickness="2" Grid.ColumnSpan="2" Grid.RowSpan="2" A sorrend azért fontos, hogy megfelelő legyen a fedése az egyes részeknek!!! Nézzzük meg az eseményvezérlőket: Mozgatás: #region Move public bool MouseDown { get; set; } public Point mouseDownPoint { get; set; } public Point mouseDownWindowPos { get; set; } private void rectDrag_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Canvas c = this.Parent as Canvas; (this.Parent as Canvas).Children.Remove(this); c.Children.Add(this); double left = Canvas.GetLeft(this); double top = Canvas.GetTop(this); mouseDownPoint = e.GetPosition(this.Parent as Canvas); mouseDownWindowPos = new Point(left, top); MouseDown = true; rectDrag.CaptureMouse(); } private void rectDrag_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { MouseDown = false; rectDrag.ReleaseMouseCapture(); } private void rectDrag_MouseMove(object sender, MouseEventArgs e) { if (!MouseDown) { return; } double left = mouseDownWindowPos.X; double top = mouseDownWindowPos.Y; Point p = e.GetPosition(this.Parent as Canvas); double deltaHorizontal = p.X - mouseDownPoint.X; double deltaVertical = p.Y -mouseDownPoint.Y; Canvas.SetLeft(this, left + deltaHorizontal); Canvas.SetTop(this, top + deltaVertical); } #endregion Vagyis egér lenyomásra megjegyzem a poziciót a Parent-hez képest (amiről tudom hogy Canvas), majd ezt felhasználom az egér mozgása eseményben. Ahol szépen beállítom a Canvas Left és Top property-jét, vagyis mozogni fog az ablak. Bezárás: private void btnClose_Click(object sender, RoutedEventArgs e) { (this.Parent as Canvas).Children.Remove(this); } Egyszerűen ki kell venni a Parent Canvas gyerekei közül... Méretezés: #region SizeWidth public bool MouseDownSizeWidth { get; set; } public Point mouseDownPointSizeWidth { get; set; } public double mouseDownWidth { get; set; } private void rectResizeWidth_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { mouseDownPointSizeWidth = e.GetPosition(this.Parent as Canvas); MouseDownSizeWidth = true; mouseDownWidth = this.Width; rectResizeWidth.CaptureMouse(); } private void rectResizeWidth_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { MouseDownSizeWidth = false; rectResizeWidth.ReleaseMouseCapture(); } private void rectResizeWidth_MouseMove(object sender, MouseEventArgs e) { if (!MouseDownSizeWidth) { return; } Point p = e.GetPosition(this.Parent as Canvas); double deltaHorizontal = p.X - mouseDownPointSizeWidth.X; this.Width = mouseDownWidth +deltaHorizontal; } #endregion #region SizeHeight public bool MouseDownSizeHeight { get; set; } public Point mouseDownPointSizeHeight { get; set; } public double mouseDownHeight { get; set; } private void rectResizeHeight_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { mouseDownPointSizeHeight = e.GetPosition(this.Parent as Canvas); MouseDownSizeHeight = true; mouseDownHeight = this.Height; rectResizeHeight.CaptureMouse(); } private void rectResizeHeight_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { MouseDownSizeHeight = false; rectResizeHeight.ReleaseMouseCapture(); } private void rectResizeHeight_MouseMove(object sender, MouseEventArgs e) { if (!MouseDownSizeHeight) { return; } Point p = e.GetPosition(this.Parent as Canvas); double deltaVertical = p.Y - mouseDownPointSizeHeight.Y; this.Height = mouseDownHeight + deltaVertical; } #endregion Hasonlóan a mozgatáshoz, itt is figyeljük az egér mozgását.Csak most nem a Top és a Left propertyt állítjuk, hanem a Height és a Width property-ket! Már csak az maradt, hogy hozunk létre egy gyerekablakot?!? SilverWindow w1 = new SilverWindow(new DemoChildWindow()); w1.Height = 200; w1.Width = 200; canvasMDI.Children.Add(w1); Erre akár készíthetünk egy általános CreateWindow statikus metódust is. És voálá... Mindenki saját ízlése és igenyei szerint fejlessze tovább!!!
Demo forráskód: http://beta.devportal.hu/groups/silverlight/media/p/744.aspx |
|
|