GSI

Expression 프로그램을 실행하다가 오류가 났다. 프로그램이 실행 되면서 바로 죽는 것이다.
DirectX 용 프로그램을 개발하다 보면 "Use Debug Version of Direct3D"로 설정해 놓고 하는게 대부분인데.. 그것 때문에 실행이 되지 않았던 것이다. ^^

Expression 용 프로그램을 테스트 하기 위해서는 "Use Retail Version of Direct3D" 로 체크 하기 바란다.

Posted by gsi
:

Where does a Binding find its data?

If you’ve look at much WPF Xaml you’ve probably seen bindings like this:

 

<TextBlock Text="{Binding Name" />

 

… which binds the Text property of the TextBlock to the Name property of some data object.

 

The question that begets is:  where does the data come from?  The rest of this post looks at the answer.

 

 

Properties on Binding

 

The Binding class has a few properties that provide ways to let you set the source of the data onto the Binding, depending on what works best for your situation.   Binding looks like this:

 

public class Binding : BindingBase

{

    ...

    public object Source { get; set; }

    public string ElementName { get; set; }

    public RelativeSource RelativeSource { get; set; }

    ...

}

 

 

The Source Property

 

The most straightforward way to set the source of the Binding is to use the Source property.  One of the more common ways to do that is to reference the data out of a resource dictionary:

 

<Grid>

  <Grid.Resources>

    <Int32Collection x:Key='DataSource1'>1,2,3</Int32Collection>

  </Grid.Resources>

 

  <ListBox ItemsSource='{Binding Source={StaticResource DataSource1}}' />

</Grid>

 

(This example creates a ListBox with 3 entries in it, labeled “1”, “2”, and “3”.)

 

You can be even more explicit by setting the Source directly, specifying the Binding in full Xml syntax (rather than the above markup extension syntax):

 

<Grid>

  <ListBox>

    <ListBox.ItemsSource>

      <Binding>

        <Binding.Source>

          <Int32Collection>1,2,3</Int32Collection>

        </Binding.Source>

      </Binding>

    </ListBox.ItemsSource>

  </ListBox>

</Grid>

 

You can also set the Binding.Source by referencing a static member:

 

namespace MyNamespace

{

    class MyClass

    {

        public static List<int> MyData;

        static MyClass()

        {

            MyData = new List<int>();

            MyData.Add(1);

            MyData.Add(2);

            MyData.Add(3);

        }

 

    }

}

 

 

<Page

    xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'

    xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'

    xmlns:my="clr-namespace:MyNamespace" >

 

  <ListBox ItemsSource='{Binding Source={x:Static my:MyClass.MyData}}' />

 

</Page>

 

 

The ElementName Property

 

Aside from the Binding.Source property, you can also reference your data by name, using Binding.ElementName, such as:

 

<StackPanel>

  <TextBox Name='TextBox1' />

  <Button Content='{Binding Text, ElementName=TextBox1}' />

</StackPanel>

 

(This example causes the button label to be whatever you type into the text box.)

 

 

The RelativeSource Property

 

The RelativeSource property provides a way to tell the Binding to look around where it’s used to find its source.  For example, the ‘Self’ RelativeSource binds to the object on which the Binding is placed, such as in the following (which creates a TextBlock that says “Hi”):

 

<TextBlock Tag='Hi' Text='{Binding Tag, RelativeSource={RelativeSource Self}}' />

 

As another example, the following binds the TextBlock.Text property to the Grid in its ancestry (again displaying “Hi” in this case):

 

<Grid Tag='Hi'>

 

  <Border Background='LightGray'>

    <TextBlock

         Text='{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType=Grid}}' />

  </Border>

 

</Grid>

 

The other two modes of a RelativeSource are TemplatedParent and PreviousData.

 

Explicit DataContext Property

 

A common way the Binding can get its source is via a DataContext property set on an element (on the element itself, not on the Binding).  For (a rather boring) example, this creates a Button that says “Click”:

 

<Button Content='{Binding}'>

  <Button.DataContext>

    <sys:String>Click</sys:String>

  </Button.DataContext>

</Button>

 

This gets more interesting and typical if you set the DataContext somewhere else, usually on the root of the page/window.  That works because the DataContext property inherits.  The following example shows that by setting the DataContext onto the root.  In this case, it is set to be an XmlDataProvider which is querying a Yahoo web service for the weather in Barrow, Alaska.  Since the DataContext inherits, Bindings throughout the page have access to it automatically.  Note also in this case that since we’re binding to XML, the Bindings are using XPath syntax.

 

<Page   

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

    >

 

  <Page.DataContext>

    <XmlDataProvider

            Source="http://xml.weather.yahoo.com/forecastrss?p=99723" 

            XPath="/rss/channel"/>

  </Page.DataContext>

 

  <Border BorderBrush="Black"

          BorderThickness="1" Width="370" Height="170" CornerRadius="6">

    <StackPanel>

 

      <!-- Image for "Yahoo! News" -->

      <Image Margin="15,15,0,0"

                   Stretch="None" 

                   HorizontalAlignment="Left"

                   Source="{Binding XPath=image/url}" />

 

      <!-- Text to say e.g. "Yahoo! Weather - Bellevue, WA", with a hyperlink to a

           detailed weather page -->

      <TextBlock Margin="15,15,0,0">

        <Hyperlink NavigateUri="{Binding XPath=item[1]/link}">

          <TextBlock Text="{Binding XPath=title}"/>

        </Hyperlink>

      </TextBlock>

 

      <!-- Text to say e.g. "Conditions for Belleveue, WA at 9:53am ..." -->

      <TextBlock FontWeight="Bold"    Margin="15,15,0,0"

                 Text="{Binding XPath=item[1]/title}"/>

 

      <!-- Weather details  -->

      <TextBlock Margin="15,0,0,0">

 

        <!-- Text to say current condition and temp -->

        <TextBlock>

          <TextBlock.Text>

            <Binding >

              <Binding.XPath>

                item[1]/*[local-name()="condition" and

                namespace-uri()="http://xml.weather.yahoo.com/ns/rss/1.0"]/@text

              </Binding.XPath>

            </Binding>

          </TextBlock.Text>

        </TextBlock>,

        <TextBlock>

          <TextBlock.Text>

            <Binding >

              <Binding.XPath>

                item[1]/*[local-name()="condition" and

                namespace-uri()="http://xml.weather.yahoo.com/ns/rss/1.0"]/@temp

              </Binding.XPath>

            </Binding>

          </TextBlock.Text>

        </TextBlock>°

        <TextBlock>

          <TextBlock.Text>

            <Binding >

              <Binding.XPath>

                *[local-name()="units" and

                namespace-uri()="http://xml.weather.yahoo.com/ns/rss/1.0"]/@temperature

              </Binding.XPath>

            </Binding>

          </TextBlock.Text>

        </TextBlock>

        <LineBreak/>

 

        <!-- Text to say sunrise/sunset times -->

        Sunrise:

        <TextBlock>

          <TextBlock.Text>

            <Binding >

              <Binding.XPath>

                *[local-name()="astronomy" and

                namespace-uri()="http://xml.weather.yahoo.com/ns/rss/1.0"]/@sunrise

              </Binding.XPath>

            </Binding>

          </TextBlock.Text>

        </TextBlock>, sunset:

 

        <TextBlock>

          <TextBlock.Text>

            <Binding >

              <Binding.XPath>

                *[local-name()="astronomy" and

                namespace-uri()="http://xml.weather.yahoo.com/ns/rss/1.0"]/@sunset

              </Binding.XPath>

            </Binding>

          </TextBlock.Text>

        </TextBlock>

      </TextBlock>

    </StackPanel>

 

  </Border>

</Page>

 

… Sunrise at midnight, sunset at noon:

 

Attachment: barrow.jpg (11494 bytes)

 

 

Implicit DataContext

 

Finally, there are a couple of places where the DataContext gets set automatically for you.  That usually happens with ContentControl (e.g. Button) and ItemsControl (e.g. ListBox). 

 

Here’s a ContentControl example.  In this markup we have a DataTemplate set up in a ResourceDictionary so that it will be used for any ContentControl that has a String as its content.  So it’s automatically picked up in the subsequent Button.  In that DataTemplate, we have a binding to the data item, which in this case is the ContentControl.Content.  Therefore what we get here is a Button that says “Click” in bold italic.

 

<Page   

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

    xmlns:sys="clr-namespace:System;assembly=mscorlib" >

 

  <Page.Resources>

    <DataTemplate DataType="{x:Type sys:String}">

      <!-- The Text property is bound to the Content property of

           whatever ContentControl with which this DataTemplate is used -->

      <TextBlock Text='{Binding}' FontStyle='Italic' FontWeight='Bold' />

    </DataTemplate>

  </Page.Resources>

 

  <Button>Click</Button>

 

</Page>

 

 

And here’s an ItemsControl example.  In this markup, we have a ListBox bound to an integer collection again (using the inherited DataContext as the source), but this time we have an item template, which is a  template to use when displaying the items in the ListBox.  And within that item template, the DataContext is again automatically set to be the item

 

<Page   

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml >

 

  <Page.DataContext>

    <Int32Collection>1,2,3</Int32Collection>

  </Page.DataContext>

 

  <!-- ItemsSource is bound to the DataContext (Int32Collection) -->

  <ListBox ItemsSource='{Binding}' >

    <ListBox.ItemTemplate>

      <DataTemplate>

 

        <DataTemplate.Triggers>

          <!-- Within the DataTemplate, the DataContext is set to be the data item.

               So this DataTrigger.Binding property's DataContext is going to be

               the item (1, 2, or 3) -->

          <DataTrigger Binding='{Binding}' Value='2'>

            <Setter Property='TextBlock.FontStyle' Value='Italic' />

            <Setter Property='TextBlock.FontWeight' Value='Bold' />

          </DataTrigger>

        </DataTemplate.Triggers>

 

        <Border Padding='10'>

          <!-- Similarly this Text property is bound to the item (1, 2, or 3) -->

          <TextBlock Text='{Binding}' />

        </Border>

      </DataTemplate>

    </ListBox.ItemTemplate>

  </ListBox>

</Page>

Posted by gsi
:

RectAnimation anima = new RectAnimation();
anima .From =
new Rect(100, 100, 200, 200);
anima .To =
new Rect(0, 0, 400, 400);
anima .Duration =
new Duration(TimeSpan.FromSeconds(1));
anima .AutoReverse =
true;
anima .RepeatBehavior =
RepeatBehavior.Forever;
AnimationClock clock = anima .CreateClock();
dc.DrawRectangle(
Brushes.Blue, null, new Rect(0, 0, 0, 0), clock);

Posted by gsi
:

xaml 코드에서 Completed="OnCompleted" 를 사용해서 에니메이션이 완료 되었을때 처리코드를 추가 할 수 있다.

<
Window.Resources>
  <
Storyboard x:Key="sb1" Completed="OnCompleted"
>
     <
DoubleAnimation  Storyboard.TargetName="deactiveAnimationRectangle" Storyboard.TargetProperty="Width" From="20" To="400" Duration="0:0:5"
/>
     <
DoubleAnimation Storyboard.TargetName="holdEndAnimationRectangle" Storyboard.TargetProperty="Width" From="10" To="400" Duration="0:0:1.5" BeginTime="0:0:0.5"
/>
</
Storyboard
>
</
Window.Resources
>

Being able, when animation ended, to set rectangle Width using: holdEndAnimationRectangle.Width = 250;

Also tried:

void OnCompleted (object sender, EventArgs e)
{
  Storyboard sb = (Storyboard)this.FindResource("sb1"
);
  sb.FillBehavior = FillBehavior
.Stop;
  holdEndAnimationRectangle.Width = 250;
}

Posted by gsi
:

<Window x:Class="WpfApplication.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="MainWindow">

    <Canvas>

        <Button x:Name="MyButton" Loaded="MyButton_Loaded">Button</Button>

    </Canvas>

</Window>

 

        private void MyButton_Loaded(object sender, RoutedEventArgs e)

        {

            const string TranslateTransformName = "MyAnimatedTranslateTransform";

 

            TranslateTransform tt = new TranslateTransform(50, 50);

            NameScope.SetNameScope(tt, new NameScope());

            this.RegisterName(TranslateTransformName, tt);

            this.MyButton.RenderTransform = tt;

 

            Storyboard sb = new Storyboard();

 

            DoubleAnimation daX = new DoubleAnimation(50, 200, new Duration(new TimeSpan(0, 0, 5)));

            daX.AutoReverse = true;

            daX.RepeatBehavior = RepeatBehavior.Forever;

            Storyboard.SetTargetName(daX, TranslateTransformName);

            Storyboard.SetTargetProperty(daX, new PropertyPath(TranslateTransform.XProperty));

            sb.Children.Add(daX);

 

            DoubleAnimation daY = new DoubleAnimation(50, 200, new Duration(new TimeSpan(0, 0, 5)));

            daY.AutoReverse = true;

            daY.RepeatBehavior = RepeatBehavior.Forever;

            Storyboard.SetTargetName(daY, TranslateTransformName);

            Storyboard.SetTargetProperty(daY, new PropertyPath(TranslateTransform.YProperty));

            sb.Children.Add(daY);

 

            DoubleAnimation daW = new DoubleAnimation(50, 200, new Duration(new TimeSpan(0, 0, 5)));

            daW.AutoReverse = true;

            daW.RepeatBehavior = RepeatBehavior.Forever;

            Storyboard.SetTargetName(daW, "MyButton");

            Storyboard.SetTargetProperty(daW, new PropertyPath(Button.WidthProperty));

            sb.Children.Add(daW);

 

            DoubleAnimation daH = new DoubleAnimation(50, 200, new Duration(new TimeSpan(0, 0, 5)));

            daH.AutoReverse = true;

            daH.RepeatBehavior = RepeatBehavior.Forever;

            Storyboard.SetTargetName(daH, "MyButton");

            Storyboard.SetTargetProperty(daH, new PropertyPath(Button.HeightProperty));

            sb.Children.Add(daH);

 

            sb.Begin(this.MyButton);

        }

Posted by gsi
:

세삼 느끼는 거지만 msdn의 예제는 너무 xaml 중심으로 되어 있다.
이런 코드의 예제가 절실하게 필요한 때인거 같다.

-- XAML CODE—

 

<Storyboard x:Key="OnCalendarLoaded">

 <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(SkewTransform.AngleX)"

Storyboard.TargetName="TargetShape">

                        <SplineDoubleKeyFrame   KeySpline="0.5,0.5,0.5,0.5" Value="0" KeyTime="00:00:00"/>

                        <SplineDoubleKeyFrame   KeySpline="0.5,0.5,0.5,0.5" Value="15" KeyTime="00:00:01"/>

            </DoubleAnimationUsingKeyFrames>

      </Storyboard>

….

          <Rectangle Stroke="White" Margin="0,20,0,0"

            Width="120" Height="100"

            x:Name="TargetShape"

            Fill="sc#0.400752217, 0.3677801, 0.3677801, 0.3677801">

              <Rectangle.RenderTransform>

                <TransformGroup>

                  <TranslateTransform X="0" Y="0"/>

                  <ScaleTransform ScaleX="0" ScaleY="0"/>

                  <SkewTransform AngleX="15" AngleY="0"/>

                  <RotateTransform Angle="0"/>

                  <TranslateTransform X="0" Y="0"/>

                  <TranslateTransform X="0" Y="0"/>

                </TransformGroup>

              </Rectangle.RenderTransform>

            </Rectangle>

 

Void StartAnimationsFunction()

{

      Storyboard story = (Storyboard)this.FindResource("OnCalendarLoaded");

      BeginStoryboard(story); // IT WORKS!

}

 


 

-- C# CODE --

 

<Storyboard x:Key="OnCalendarLoaded">

      </Storyboard>

 

 

Void StartAnimationsFunction ()

{

      Storyboard story = (Storyboard)this.FindResource("OnCalendarLoaded");

story.Children.Add(getAnimation1("TargetShape"));

      BeginStoryboard(story); // NOTHING HAPPENS!

}

       

        private DoubleAnimationUsingKeyFrames getAnimation1(string name)

        {

            DoubleAnimationUsingKeyFrames anim = new DoubleAnimationUsingKeyFrames();

            anim.BeginTime = new TimeSpan(0, 0, 0);

 

            Storyboard.SetTargetName(anim, name);

            Storyboard.SetTargetProperty(anim,

                new PropertyPath("0.1[2].2", new DependencyProperty[] {

                    UIElement.RenderTransformProperty,

                    TransformGroup.ChildrenProperty,

                    SkewTransform.AngleXProperty}));

 

            anim.KeyFrames.Add(new SplineDoubleKeyFrame(0, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0)), new KeySpline(.5, .5, .5, .5)));

            anim.KeyFrames.Add(new SplineDoubleKeyFrame(15, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 1)), new KeySpline(.5, .5, .5, .5)));

 

            return anim;

        }

Posted by gsi
:

사용자 삽입 이미지

[작업 경위]

--xaml 파일--
1. Blend를 사용해서 기본 베이스 제작
   - 해당 경로를 입력 받을 수 있도록 TextBox를 추가
   - 경로 이미지를 가져 오기 위한 Button를 추가
   - 이미지를 보여 주기 위한 ListBox를 추가
2. 템플릿 변경
   - ListBox > StackPanel > TextBlock
                                       Border > Image
     위와 같이 파일 이름과 이미지를 보여 주기 위한 테플릿을 하나 제작하였다.
     이 부분은 상세하게 적지 않는다. (lynda 페이지의 blend 항목에 가면 자세히 나와 있음)
3. 리스트 정보를 저장할 CLR 클래스를 하나 생성한다.
   - Name, Path 정보를 담고 있는 클래스이며, 배열로 사용하기 위해서 ObservableCollection 를 사용하였다.
   - xaml 파일로 클래스 연동시킨다.
     xmlns:c="clr-namespace:GsiImageView" //클래스 네임스페이스 추가
     <Window.Resources>
        <c:PathInfoList x:Key="pathData" /> //를 추가 한다.

--cs 파일--                
1. 스레드를 사용하기 위해서 네임 스페이스 추가
   - using System.Threading;
2. xaml 파일의 버튼 클릭 이벤트를 생성한다.
        private void OnFolderOpenClick(object sender, RoutedEventArgs e)
        {
            Thread loadThread = new Thread(new ThreadStart(DataLoad));
            loadThread.Start();
            Thread.Sleep(1);
        }
3. 스레드에 사용할 함수를 하나 만든다. 이 함수내부에서 폴더 내의 이미지를 읽어서 작업 하도록 한다.
        private void DataLoad()
        {
            .....
        }
4. 메인 스레드의 인스턴스된 객체를 접근 하기 위해서 delegate를 선언한다.
        public delegate void UpdateImage(string _path);
5. Invoke에 사용할 함수를 추가 한다.
        public void UpdateImageList(string _path)
        {
            PathInfoList pathinfolist = (PathInfoList)this.FindResource("pathData");
            pathinfolist.Add(new PathInfo(_path, "none.jpg"));
        }
6. DataLoad() 함수 안에 내용을 추가 한다.
        private void DataLoad()
        {
            //디렉토리 경로 가져 오기
            DirectoryInfo di = new DirectoryInfo(@"D:\WPF_Project\GsiImageView\Image\MaxImageTest");
            try
            {
                if (di.Exists)
                {
                    //경로가 있음
                    foreach (FileInfo fi in di.GetFiles())
                    {
                        //경로를 타고 세부 이미지 이름을 얻어 온다.
                        string path = di.FullName + "\\" + fi.Name;

                        this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.DataBind, new UpdateImage(UpdateImageList), path);

                        Thread.Sleep(60);
                    }
                }
                else
                {
                    MessageBox.Show("경로가 확실하지 않습니다.");
                    return;
                }
            }
            catch
            {
                MessageBox.Show("경로가 확실하지 않거나, 비정상 오류 입니다.");
                return;
            }
        }


몇개더 구현되어야할 내용입니다.
1. 경로 입력후 해당 경로에 맞는 이미지 찾아 오기
2. 경로 내부의 서브폴더까지 찾아서 이미지 추가 하는 방법 구현하기
3. ListBox의 그룹별 소트 방법 및 재정렬 방법 구현하기
4. 미리 목록을 얻어 와서 드로잉 하고 세부 이미지 부분만을 여러개의 스레드를 사용해서 구동되는 형태로 구현하기
5. 미정...


<해당 데모>


Posted by gsi
:

WPF를 공부 하면서 무언가 만들어 보는 목적이 없다면 공부에 쉽게 지치게 되고 시간을 허비 하게 되는거 같다.
그래서 시작 하였다. "WPF 프로젝!!" 폴더 안의 카테고리는 데모를 제작해 보면서 공부를 하고 데모를 배포 하며, 다른 사람으로 하여금 사용될 수 있는 것을 목표로 한다.

저작권은 본 IamGsi 플로그에 있으며, 배포 또는 사용하는데 있어서 제약이 없습니다.
수정사항이 있거나 아이디어가 있으신 분은 피드백을 해주시면 감사하겠습니다.
단, 상업적인 목적으로 할때는 연락을 주시면 감사하겠습니다.

[프로그램 소개]
본 프로그램은 해당 폴더에 있는 이미지를 화면에 보여 주는 형식입니다.

Posted by gsi
:

타이머 사용하기

WPF 2007. 9. 10. 23:15 |

본 글은 http://www.hoons.kr 에 있는 내용을 나름대로 이해되는 부분에 한해서 적은 것입니다.

타이머 사용을 위해서 네임 스페이스를 하나 선언합니다.
using System.Windows.Threading;

타이머 변수를 하나 선언합니다.
DispatcherTimer dt = new DispatcherTimer();

그리고 난수를 하나 생성하게 됩니다.
Random ran = new Random();

이후에 코드에 맞는 해당 값들의 전역 변수들을 선언 하면 됩니다.

dt의 타이머를 사용하기 위해서 초기 설정을 하게 됩니다.
dt.Interval = TimeSpan.FromMilliseconds(30);
dt.Tick += new EventHandler(dt_Tick);
dt.Start();


Tick에 추가한 이벤트 핸들러에 대한 함수 원형을 추가 합니다.
void dt_Tick(object sender, EventArgs e)
{
   .....
}


..... 이상 코드는 여기까지.......

Start()를 하고 나면 계속해서 타이머가 동작 하게 됩니다.
타이머 동작을 멈추고 싶다면 dt.Stop()를 해주면 됩니다.


이후에 참고할 만한 코드는

* 랜덤 함수는 ran.NextDouble() 를 사용해서 double형 값을 가져 올수 있습니다.
   물론 double 말고도 int형을 가져 오는 함수도 존재 합니다.
* Canvas에 있는 오브젝트의 위치를 변경하기 위해서 아래와 같은 코드가 가능해 집니다.
   Canvas.SetLeft(im, currX);
   Canvas.SetTop(im, currY);
   - im은 Canvas에 있는 객체의 Name 이며, currX, currY 는 전역 변수로 가지고 있는
     위치가 되겠습니다.
* 해당 값의 절대값을 사용하기 위해서 아래의 코드를 사용합니다.
    if (Math.Abs(currX - destX) < 1)
    {
        destX = ran.NextDouble() * this.ActualWidth;
        destY = ran.NextDouble() * this.ActualHeight;
    }




Posted by gsi
:

Blend의 튜토리얼 중에 ColorSwitch 라는 예제가 있다.
그곳에서 보면 칼라 스위치는 마우스가 Enter 되면 앞쪽으로 나오게 된다.
이 부분은 SetZIndex 가 담당하게 되는데.
조작 하는 방법이 조금은 다르다.

Blend에서 Grid 내부에 Canvas를 3개를 겹치게 배치 했다가 가정하겠다.
여기서 우리는 원하는 Canvas를 제일 위쪽에 가져다 놓기를 바랄때가 있을것이다.
이때 사용하는게 SetZIndex를 사용하면 된다.

하지만 이것은 Name를 가지는 객체에 포함되어져 있는 함수는 아니기 때문에 아래의
코드를 이용해야 한다.

관련msdn 로컬 주소 : http://msdn2.microsoft.com/en-us/library/system.windows.controls.panel.zindex.aspx

Canvas.SetZIndex(Step0, 1);

위와 같은 코드를 사용할 수 있다.
Canvas를 객체의 SetZIndex를 변경해준다고 생각하면 되며,
Grid 내부에 Canvas가 여러개 있을때 사용하게 되는 것이다.
즉, Grid 내부의 Canvas를 이동시키고자 할때는

Canvas.SetZIndex()를 사용하면 되는 것이다.

Step0이라는 것은 Blend에서 Canvas의 이름을 의미한다.

그리도 뒤에 오는 1이라는 숫자는
Blend에서 여러개의 객체를 배치 하고 나서 ZIndex를 보면 모두 0인 것을
알수 있다. 이 경우에 0 이지만 배치된 순서대로 화면에 표현되도록 되어 있다.
그래서 1이라는 숫자는 최상단에 배치 한다고 생각 하면된다.

다른 방법으로 3개의 객체가 있다고 했을때 0 ~ 2까지 3개의 ZIndex를
사용해도 된다.

간단하게 하기 위해서는 모두 0이고 최상단에 올려질것만 1로 설정하면
편하게 할 수 있을거 같다.

Posted by gsi
:

버튼 위치 이동시키기.

WPF 2007. 9. 9. 05:39 |

Button을 이동시키기 위해서는 Margin의 값을 잘 살펴 보면 된다.
이 값이 어떤 Property이고 어떻게 이동해 주어야 하는지 찾아야 한다.

참고로 Button의 Name가 MoveObject 라고 가정하고 시작한다.

Blend에서 Button을 하나 생성한 후에 마우스로 이동해 보자.
그러면 Margin의 값이 바뀌는 것을 알수 있다. 즉 Left, Top의 값이 바뀌게 되는 것이다.
그렇다면 비아인드 코드를 작성 할려면 Margin에 특정 값을 넣어 주면 되는 것이다.

MoveObject.Margin.Left 라는 속성이 있지만 이것은 특정 int, double의 값을 추가할수는 없다.

그래서 cs 파일의 MoveObject.Margin의 툴팁 정보를 보니
FrameworkElement.margin property 라고 나오는 것을 볼 수 있었다.
그래서 msdn에서 FrameworkElement.margin을 찾아 보았다.

아하! Syntax 에 보니
C#
public Thickness Margin { get; set; }
이런 구문을 볼 수 있었다. 바로 Thickness를 하나 생성한 후에 값을 추가 하고
Margin에 대입해 주면 되는거라고 짐작이 될것이다.

그래서 아래와 같은 코드를 사용해서 하면 된다.

Thickness th = new Thickness(marginleft, margintop, 0, 0);
MoveObject.Margin = th;
이상.  (msdn을 잘 활용하자. 거의 모든 코드가 다 있다. ^^)
Posted by gsi
:

랜덤 코드 사용하기

WPF 2007. 9. 9. 05:34 |

네임스페이스 선언 : using System.Threading;

코드 사용방법 :

Random autoRand = new Random();
double marginleft = autoRand.NextDouble() * (this.Width - MoveObject.Width);
double margintop = autoRand.NextDouble() * (this.Height - MoveObject.Height);

Thickness th = new Thickness(marginleft, margintop, 0, 0);
MoveObject.Margin = th;

Next()는 int형 정보를 가져올때 사용한다.
NextDouble()는 double형 정보를 가져 올때 사용한다.

이후에도 seed의 값을 입력 하는 방법도 있으니 참고 하기 바란다.

Posted by gsi
:

UIElement3D extensibility - 3D Video Carousel

Recently I've been working on a screencast, which goes over some advanced aspects of working with Element3D. In the meantime, this sample demonstrates WPF's Orcas Beta 2 UIElement 3D technology, covering the essentials for how you can make your own reusable UIElement3D controls for 3D. I have two in here:

  1. A "KeepCaseUIElement3D", a representation of a real world DVD case, with the added twist of playing video on the inside. It's API consumes Uri's for cover images and a media source, rather than traditional models, meshes, and materials in 3D .
  2. A "MovieCarousel" - a simple 3D carousel layout control which re-orients itself to position the object which was last clicked towards the user.

You will need to operate with the WPF V3.5(Orcas) Beta 2 Bits. You can get the Visual Studio Orcas Beta 2 installation with WPF from here.

A set of streaming WPF tutorial Videos

Concepts you can see in practice with this sample include:

  • Creating interactive 3D controls as interactive containers on non-interactive 3D models (Hint - Leverage existing 3D Xaml with little effort)
  • Creating a Custom Visual3D container type
  • Use of StaticResources from Application.Resources to separate mesh details from overall structure
  • Databinding a mesh texture to consume a local DP exposed as a URI, via a data binding type converter
  • 3D Layout - Cylinder Layout Helper class
  • Playing Video as a material on 3D

If you have any questions on the details of this sample, feel free to send me a message, or leave a relevant comment- odds are fair other folks have similar questions, which could make for interesting future blog postings!

 Thanks!

관련자료 : http://blogs.msdn.com/pantal/archive/2007/08/22/uielement3d-extensibility-dvd-keep-case-player-cylindrical-carousel-layout.aspx

Posted by gsi
:

What’s new in WPF 3.5

WPF 2007. 9. 7. 09:29 |

What’s new in WPF 3.5

With the release of WPF 3.5 beta 2 (download here: http://www.microsoft.com/downloads/details.aspx?FamilyId=D2F74873-C796-4E60-91C8-F0EF809B09EE&displaylang=en), we’ve added some exciting new features to WPF 3D.  At a very high level these can be grouped in to two main additions: UIElement3D and Viewport2DVisual3D.  Over the next couple of weeks we’ll be adding examples and tips and tricks to the blog on these new additions, but for now we’ll start with a quick overview of what both of these provide.

UIElement3D

In the 2D world, UIElement adds layout, input, focus and eventing on to Visual.  UIElement3D brings these same things (except no layout) to 3D.  What this means is that the standard events and means of adding event handlers that you’re used to with UIElements now applies in the 3D world with UIElement3D. 

UIElement3D itself is an abstract class that derives from Visual3D.  To make it useable out of the box without having to derive from UIElement3D yourself, we’ve provided two new classes:  ModelUIElement3D and ContainerUIElement3D. 

ContainerUIElement3D does exactly what its name says.  It is a container for other Visual3Ds.  It has one main property, Children, which is used to add and remove 3D children.  The ContainerUIElement3D doesn’t have a visual representation itself, but rather is just a collection of other 3D objects.

ModelUIElement3D has one property, Model, which is the Model3D that should be displayed to represent the UIElement3D.  It has no children itself, and in some ways you can think of ModelUIElement3D like a Shape in the 2D world.

If you’re familiar with ModelVisual3D, then ContainerUIElement3D and ModelUIElement3D should look very familiar.  The difference is we’ve gone and split the functionality of ModelVisual3D (i.e. a model and children) in to two separate classes, one with a model and the other with children.

With these then, making use of layout, focus and eventing is very easy.  For instance, say you want to create a 3D object that responds to mouse events, you can just do:

                <ModelUIElement3D  MouseDown="OnMouseDown"/>

And then in the code behind have:

      protected void OnMouseDown(object sender, MouseButtonEventArgs e)

      {

          Console.WriteLine("Hello");

      }

If you have experience adding event handlers in the 2D world, then this should look immediately familiar.  In fact it’s exactly the same, and UIElement3D is going to handle the same routed events that a UIElement deals with.  With the addition of UIElement3D you now get all the great functionality that UIElement provided to 2D, but now in the 3D world!

Viewport2DVisual3D

The second main addition is Viewport2DVisual3D which enables you to put interactive 2D on 3D in WPF.  If you’ve used the 3DTools work that was released shortly after the 3.0 release of WPF, Viewport2DVisual3D will look very familiar to you.  With 3.5 though we’ve fully integrated 2D on 3D in to WPF rather than requiring a separate DLL to have this feature.  The 2D and 3D trees are also integrated now, so if you walk up to a 2D visual on 3D and ask it for its parent, it will tell you the 3D object it is on.

Viewport2DVisual3D derives from Visual3D and has three main dependency properties: Visual, Geometry and Material.

Visual – This is the 2D Visual that will be placed on the 3D object.

Geometry – The 3D geometry for the Viewport2DVisual3D

Material – This describes the look of the 3D object.  You can use any material you want.  For the material that you want to have the Visual be placed on, you simply need to set the Viewport2DVisual3D.IsVisualHostMaterial attached property to true.

Below is a XAML example using Viewport2DVisual3D

<Viewport2DVisual3D Geometry="{StaticResource plane}">

        <Viewport2DVisual3D.Material>

          <DiffuseMaterial  Viewport2DVisual3D.IsVisualHostMaterial="true" />

        </Viewport2DVisual3D.Material>

       

        <Button>3.5!</Button>          

      </Viewport2DVisual3D>

The above is a very quick overview of what is added in 3.5, so expect more posts on more specific details as well as some code samples on how to use it.

-Kurt Berglund

Posted by gsi
:

Of course I couldn't mention a technique of possible real-time cell-shading yesterday without actually trying it out. No, I didn't attempt to derive from BitmapEffect. (I'd love to take a crack at BitmapEffect but I simply cannot justify the expenditure of time.)

Instead, I tried the RenderTargetBitmap approach. Here's a rough outline:

  • Lay out your Page or Window normally but instead of defining a Viewport3D element, use a Border instead. The Border is perhaps the simplest FrameworkElement derivative that has a Background property. Give the Background property an object of type ImageBrush.
  • Whatever you would have put into your Viewport3D put into a Viewport3DVisual instead. Set the Viewport property of the Viewport3DVisual to the actual size of the Border element. You'll need a handler for the SizeChanged event of the Border to keep this Viewport property updated when the Border size changes.
  • In that same SizeChanged event handler for the Border, create an object of type RenderTargetBitmap the same size as the Border and the Viewport3DVisual. You'll be recreating this bitmap whenever the size of the Border changes.
  • Insteall event handlers for anything else (such as scrollbars) that affect the 3D scene defined within the Viewport3DVisual.
  • Whenever anything happens that affects the appearance of the Viewport3DVisual perform the following actions:
    • Clear the RenderTargetBitmap by calling the Clear method.
    • Render the Viewport3DVisual on the bitmap by calling the Render method.
    • Dump the pixel bits of the RenderTargetBitmap into an array by calling CopyPixels.
    • Do whatever processing you want on the pixel bits. (For cell-shading, I just AND-ed each 32-bit ARGB pixel with 0xFFC0C0C0.)
    • Create a new bitmap based on the altered pixel bits by calling BitmapSource.Create.
    • Set that new bitmap to the ImageSource property of the ImageBrush object set to the Background property of the Border.

Here's the RealTimeCellShading source code. Sorry I can't give you an XBAP, but apparently Clear and CopyPixels are prohibited methods for partial trust. (But Render and BitmapSource.Create are mysteriously OK. Hey — I don't make up the XBAP rules!)

I've used an AmbientLight at 1/4 white and DirectionalLight of 3/4 white with a direction of (2, –3 –1). I've provided a pair of scrollbars to rotate the camera relative to the teapot, and a pair of sliders to rotate the teapot relative to the camera and light sources. Here's a view with the teapot slightly rotated:

Posted by gsi
: