WPF一步一脚印系列(1):万事起头难

一直从事Asp.Net的开发,而C/S的开发方面简直是一片空白,于是从上星期开始就痛下决心开始学习WPF。我采取的策略是网上看基础资料+做
简单的demo练习+网上查资料。从csdn上下了个比较不错的基础讲解文档,花了几天时间终于把它看完,算是有个基本了解吧,今天开始写些小练习。

  这个系列主要是用来记录自己学习WPF的心路历程,以实例为主配合原理和注意点的说明,有纰漏之处请大家多多指正!!^_^


例1——倒计算器                                 


最终效果:

Window1.xaml:

<Window x:Class="CountingLeader.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <StackPanel.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="FontSize" Value="50"></Setter>
                </Style>
            </StackPanel.Resources>
            <TextBlock x:Name="tbkHour" Text="00"></TextBlock>
            <TextBlock Text=":"></TextBlock>
            <TextBlock x:Name="tbkMinute" Text="10"></TextBlock>
            <TextBlock Text=":"></TextBlock>
            <TextBlock x:Name="tbkSecond" Text="45"></TextBlock>
        </StackPanel>
    </Grid>
</Window>

Window1.xaml.cs:

namespace CountingLeader
{
    /// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
    public partial class Window1 : Window
    {
        private CountingLeaderManager clm = null;

        public Window1()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Window_OnLoaded);
            clm = new CountingLeaderManager();
        }

        public void Window_OnLoaded(object sender, RoutedEventArgs e)
        {
            clm.TotalCount = Convert.ToInt32(this.tbkHour.Text) * 3600 +
                Convert.ToInt32(this.tbkMinute.Text) * 60 +
                Convert.ToInt32(this.tbkSecond.Text);

            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0,0,1);
            timer.Tick += (ss, ee) =>
                {
                    if (clm.CanReduce())
                    {
                        clm.Reduce();
                        this.tbkHour.Text = clm.GetHour();
                        this.tbkMinute.Text = clm.GetMinute();
                        this.tbkSecond.Text = clm.GetSecond();
                    }
                    else
                        timer.Stop();
                };
            timer.Start();
        }
    }
}

CountingLeader.cs:

namespace CountingLeader
{
    public class CountingLeaderManager
    {
        public int TotalCount { get; set; }

        public bool CanReduce()
        {
            if (TotalCount == 0)
                return false;
            else
                return true;
        }

        public int Reduce()
        {
            return --TotalCount;
        }

        public string GetHour()
        {
            return GetCount(() => TotalCount / 3600 );
        }

        public string GetMinute()
        {
            return GetCount(() => TotalCount % 3600 / 60);
        }

        public string GetSecond()
        {
            return GetCount(() => TotalCount % 60);
        }

        private string GetCount(Func<int> func)
        {
            string result = string.Empty;
            int resultInt = func();
            if (resultInt <= 9)
                result = "0" + resultInt;
            else
                result = resultInt.ToString();

            return result;
        }
    }
}

wf时期的有三种计时器供大家使用:System.Threading.Timer、System.Timers.Timer和
System.Windows.Forms.Timer,如果计时器用在UI上那么就使用System.Timers.Timer,因为它由UI线程实
现;如果实现与UI无关的操作可以用System.Threading.Timer,它是从系统的线程池中取线程实现计时器的功能,但因不是用UI线程实
现而无法操作UI上的控件;而System.Timers.Timer是由服务器实现,具体有待研究。

而该练习使用的计时器是System.Windows.Threading.DispatcherTimer,.net frameword 3.0后提供,感觉像是wf中的System.Windows.Forms.Timer。

注意:由UI线程实现的计时器会阻塞UI的交互操作。

1 timer.Tick += (ss, ee) =>
2     {
3          System.Threading.Thread.Sleep(100000);
4     };

将Window1.xaml.cs文件中的timer.Tick部分修改为上述代码后,明显看到计时器跟UI交互操作使用的同一个线程。


例2:简易多媒体播放器                                                              
                                                                   

最终效果:

 

Window1.xaml:

 

<Window x:Class="VideoPlayer.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <Border Background="Gray">
            <Border.BorderBrush>
                <SolidColorBrush Color="Silver"></SolidColorBrush>
            </Border.BorderBrush>
            <MediaElement x:Name="me" LoadedBehavior="Manual" MinHeight="200"
                          Volume="{Binding ElementName=volumeSlider,Path=Value}"></MediaElement>
        </Border>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <StackPanel.Resources>
                <Style TargetType="Button">
                    <Setter Property="Background">
                        <Setter.Value>
                            <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                <LinearGradientBrush.GradientStops>
                                    <GradientStopCollection>
                                        <GradientStop Color="White" Offset="0.1"></GradientStop>
                                        <GradientStop Color="#232323" Offset="1"></GradientStop>
                                    </GradientStopCollection>
                                </LinearGradientBrush.GradientStops>
                            </LinearGradientBrush>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Margin" Value="2"></Setter>
                    <Setter Property="FontStyle" Value="Italic"></Setter>
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Foreground" Value="Gold"></Setter>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="Gray"></Setter>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </StackPanel.Resources>
            <Button x:Name="btnOpenFile" Content="Open File" Click="btnOpenFile_Click"></Button>
            <Button x:Name="btnPlayOrPause" Content="Play" Click="btnPlayOrPause_Click" IsEnabled="False"></Button>
            <Button x:Name="btnStop" Content="Stop" Click="btnStop_Click" IsEnabled="False"></Button>
            <Button x:Name="btnBack" Content="Back" Click="btnBack_Click" IsEnabled="False"></Button>
            <Button x:Name="btnForward" Content="Forward" Click="btnForward_Click" IsEnabled="False"></Button>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Volume:"></TextBlock>
            <Slider x:Name="volumeSlider" Maximum="1" Minimum="0" Value="0.5" Width="200" ></Slider>
        </StackPanel>
    </StackPanel>
</Window>

说明:

1.MediaElement的Volume(声音)是依赖属性可以使用Slider作为数据源将Slider的Value值绑定到MediaElement;

2.Style中Trigger用来设置按钮的不可用、鼠标在上面时样式的变化。

Window1.xaml.cs:

 

namespace VideoPlayer
{
    /// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
    public partial class Window1 : Window
    {
        private bool IsPlaying = false;

        public Window1()
        {
            InitializeComponent();
        }

        private void btnOpenFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "mp3文件(*.mp3)|*.mp3|wmv文件(*.wmv)|*.wmv|avi文件(*.avi)|*.avi";
            if(ofd.ShowDialog()==System.Windows.Forms.DialogResult.OK)
            {
                this.me.Source = new Uri(ofd.FileName, UriKind.Absolute);
                this.btnForward.IsEnabled = true;
                this.btnBack.IsEnabled = true;
                this.btnPlayOrPause.IsEnabled = true;
                this.btnStop.IsEnabled = true;
            }
        }

        private void btnForward_Click(object sender, RoutedEventArgs e)
        {
            this.me.Position += TimeSpan.FromSeconds(10);
        }

        private void btnBack_Click(object sender, RoutedEventArgs e)
        {
            this.me.Position -= TimeSpan.FromSeconds(10);
        }

        private void btnPlayOrPause_Click(object sender, RoutedEventArgs e)
        {
            if (IsPlaying)
            {
                this.me.Pause();
                (sender as System.Windows.Controls.Button).Content = "Play";
                IsPlaying = false;
            }
            else
            {
                this.me.Play();
                (sender as System.Windows.Controls.Button).Content = "Pause";
                IsPlaying = true;
            }
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            this.btnPlayOrPause.Content = "Play";
            this.me.Stop();
            IsPlaying = false;
        }
    }
}

说明:

1.这里使用了System.Windows.Forms.OpenFileDialog控件,如果针对Window7开发可以使用WindowsAPICodePack;

 

以上是今天做的练习,十分简单最适合像我这样的初学者了,一步一个脚印坚持不懈!!

时间: 2024-09-15 01:22:31

WPF一步一脚印系列(1):万事起头难的相关文章

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十二)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十二) 雷.混.冰.毒.火.风 - 幻化中的魔法魅力 本节,我将为大家演示如何为游戏中的魔法增加华丽的附加属性. 第一步,定义规则: 1)定义魔法附加属性分类:在本教程示例游戏中,我将魔法附加属性定义为6类:雷.混.冰.毒.火.风,为什么要以这样无规律的方式去命名?因为是教程,我们需要学习的是如何实现对应效果,此6类属性算是目前网游中最流行的六大魔法属性,如果大家都掌握了,无论是中国式5行还是诸如其他的风格设

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十一)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十一)制作精美的Mini地图① 用什么来承受未来几个月日思夜想的折磨?除了学习还是学习. 感慨了一翻,嘿嘿.本节我将为大家讲解如何为Silverlight游戏制作一个精美的Mini地图.Mini地图又分两种,一种是通常处于游戏窗口右上角的Mini雷达(导航)地图:另一种是全景Mini寻路地图.本节我先向大家讲解如何制作导航Mini雷达地图.此类地图在游戏中主要起到导航作用,即引导主角前行的方向,并且呈现出

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十八)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十八)地图间的传送与切换 终于到了地图处理的最后一节,本节我将为大家讲解如何通过传送点实现主角在地图间的传送以及地图之间的切换.地图转换的关键在于把握好移除与添加:即移除之前地图上除主角之外的所有对象,然后再重新加载新地图上的所有对象.本教程示例游戏中,每张地图的信息都详细的记录于Config.xml配置文件中,包括每张地图的表层.遮挡层.障碍物层等等,然后再附加上本节后面将向大家讲解的传送点信息:这样,

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十四)地图编辑器诞生啦! 到目前为止,教程示例游戏中虽然实现了A*,但是还无法轻松的为地图设置障碍物:并且游戏所有地图均为一张整的大图片,主角的移动会导致窗体对地图的不停切割,越大的地图带来的负面性能损耗越明显.对地图进行切片处理则可达到性能的最大优化:载入的时候按需加载,地图根据主角的位置仅显示特定部份:并且如果还能配上任意勾勒的遮挡物,那么这一切的一切将更能完美的诠释我们的游戏.开发制作地图编辑器已迫在眉

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(十四) 精灵控件横空出世!① 在上一节中,我们实现了地图牵引式移动,同时还遗留着一个小尾巴:主角和障碍物该如何跟随着地图的移动而移动? 上节中有点到,只要在地图移动的同时,时时根据主角等对象物体的X,Y坐标进行相对于地图的X,Y坐标移动即可达到目的.但是由此又引来了新问题:主角为Image控件,障碍物则为矩形控件,它们都没有X,Y这两个属性,我们该如何对它们的坐标进行记录呢? 最简单且最直接的方法莫过于将它们的

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)制作精美的可任意拖放对象的物品栏及装备栏 在通常的网络游戏中,物品.装备.技能.快捷按钮等窗口中的图标都是可以相互拖放的,不同的栏目有着不同的限制,例如技能图标不能拖放到物品栏及装备栏中,且不是所有的魔法技能都可以拖放(如被动技能等):而非装备类的所有物品则无法拖放到角色的装备栏中.那么本节我将向大家讲解如何在本教程示例游戏中添加物品栏及装备栏,并实现它们之间双向物品交换的两种模式:拖放模式和双击模

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)制作主角属性面板及加点器 游戏中会使用大量的菜单面板,而这些面板往往都带有选项卡.如果用Silverlight工具中的TabControl,则需要通过复杂的xaml重写模板来实现自定义样式,这一点时常让开发者头疼,毕竟界面的东西应该属于美工的范畴,这也是我所发现在目前Silverlight中唯一一处只能通过xaml而无法用代码实现的地方.当然,如果您对此特别感兴趣,同样可以到http://www.c

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十三)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十三)制作游戏主菜单面板及鼠标左右键快捷技能栏 每款MMORPG都有一个主菜单,通常置于窗口的底部.游戏中主角大部分的设置操作都从这里开启.如人物属性.物品(包裹).技能.任务.队伍.地图.家族.门派.商城.系统设置等等:当然,还包括快捷自定义菜单栏,以及类似<暗黑破坏神>中经典式的左右键快捷技能栏.这些内容在不同的游戏中往往会根据自身的特性稍做调整,但整体上大同小异.本节,我将同样以<剑侠世界&

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十二)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十二)制作精美的Mini地图② 前面章节中讲解的包括对象头像面板.Mini雷达地图等窗体都是位置固定的,在处理起来方式多样且简单:而RPG.SLG.休闲养成等类型的游戏中往往会大量使用到悬浮且可自由拖动的窗体,比如包裹面板.武器装备面板.个人属性面板.技能面板.系统设置面板等等,这就要求我们必须为游戏量身定做一个通用且易用的ChildWindow控件.那么本节我将为大家讲解如何制作一个包含可拖动头部.关闭