• [WPF]设置背景色


    程序效果

    最终得到程序的运行效果如图。拖动Slider可以使按钮的背景色出现相应变化。

    需求分析和架构设计

    如果是你,接到了这样的一个程序设计要求,会怎样思考?
    第一步当然是需求分析啦。这个程序相对简单,需要分析的主要是各个控件之间的数据联系。这主要体现在Slider, Textbox和Button间的同步关系上:
    拖动Slider的滑块,要求TextBox里的数值也要变化,同时Button的背景色也要发生相应变化。改变TextBox里的值,滑块的位置和Button的背景也要做相应调整。
    一个习惯于WinForm的同学就会有很自然的想法——处理消息(.NET表现为事件)呗。对Slider滑块的滑动这个事件,设置一个EventHandler,以更新Textbox的Text属性和Button的Background属性。对于Textbox.Text的更改这个事件,设置一个EventHandler,更新Slider的Value属性和Button的Background属性。
    很好。下面我们就来看一下在WPF中,思维可以变得如此不同而简单。

    实现过程

    第一步自然是创建工程。首先在Visual Studio 2008下,新建一个工程,选择Visual C#里面的WPF Application即可。

    稍等片刻就可以看见一个工程被创建,同时默认的窗体设计文件Windows1.xaml被显示出来了。注意虽然XAML中可以像MFC那样用图形化的方式放置控件,但是由于XAML的功能太强大,图形化界面很难完全表达,因此在目前的版本中主要还是采用代码的方式进行界面设计。不过微软已经放风说在Visual Studio 2010中这样的情况会加以改善。
    第二步是设计UI。首先在XAML代码中<Grid></Grid>间插入:

    复制代码
    <Grid.RowDefinitions>
    <RowDefinition /> <RowDefinition />
    <RowDefinition /> <RowDefinition />
    <RowDefinition /> </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="50" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="50" />
    </Grid.ColumnDefinitions>
    复制代码

    这一段代码主要是将整个界面唰唰切成5行3列一共15个大块,在设计界面中可以很清楚的看到(如下图)。其中最左边和最右边这两列固定为50像素,中间那一列是宽度可变的。

    下面就要往里面放控件了。在</Grid.ColumnDefinitions>和</Grid>间继续加入以下代码:

    <TextBlock Grid.Column="0" Grid.Row="0">Red</TextBlock> <Slider Grid.Column="1" Grid.Row="0"/> <TextBox Grid.Column="2" Grid.Row="0"/>

    这是在第一行的第一个格子里放了一个TextBlock控件,用来显示那个Red。然后在同一行的第二个格子里放了一个Slider,第三个格子里放了一个TextBox。现在设计界面是这样的:

    看起来好丑哦。没关系我们来修饰一下。
    首先窗口太大了,把XAML文件中第四行中Window1的Height改成200先。然后每个控件把格子占得满满的,影响美观。在各个控件中加入Margin="5",比如Slider控件的代码现在看起来应该是这样的:
    <Slider Grid.Column="1" Grid.Row="0" Margin="5"/>
    这样就使得空间和格子间有一定的间距,看起来舒服一点。
    然后将各个控件的垂直对齐方式设为中间对齐,加入VerticalAlignment="Center"即可。好的,现在蛮漂亮的了。

    代码看起来应该是这样:

    <TextBlock Grid.Column="0" Grid.Row="0" Margin="5" VerticalAlignment="Center">Red</TextBlock>
    <Slider Grid.Column="1" Grid.Row="0" Margin="5" VerticalAlignment="Center"/>
    <TextBox Grid.Column="2" Grid.Row="0" Margin="5" VerticalAlignment="Center"/>

    下面我们来加入其余三个TextBlock, Slider和TextBox。分别代表Green, Blue, Alpha值。将以上代码复制粘贴三份即可。注意每一行都要相应修改Grid.Row值。第二行为1,以此类推。不要忘了把后面几行TextBlock里的Red改成相应的Green, Blue等等哦。现在界面看起来像这样:

    最后需要在最后一行加入一个Button。在</Grid>前添加如下代码:

    <Button Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="4" HorizontalAlignment="Center" Width="100" Margin="5"> <Rectangle Width="10" Height="10" Fill="Red"/> </Button>

    很容易看懂这是说要添加一个宽度100像素,水平中央对齐,在第5行的按钮。按钮的内容是一个长宽各为10,红色的方形。只是要注意Grid.ColumnSpan="3"表示这一个控件将占用3列的空间。

    再把Window1的Title改成ColorChange。至此UI的设计就结束了。如下图。

    呼,界面设计说起来还是比较繁琐的。终于进入WPF强大的地方了。首先是界面设计的时候注意到了吗?Button的内容可以是一个方块诶!如果我告诉你还能是其他控件比如是一个slider外加一个TextBox呢?就像这样:

    要是在MFC里面还不要搞死人。最简单的情况是通过改CButton的bitmap来实现在按钮上显示图片。就算只想在里面嵌入一个Slider,就首先要继承CButton类,然后广大人民充分发挥聪明才智吧,拼死拼活总算搞出来一种控件叫做CSliderButton。然后一拍脑袋,哎呀我搞错了,其实我想嵌入一个TextBox的。好吧,大返工……但是在WPF里如此简单,我们要做的仅仅是把<Rectangle />换成其他控件就好了,比如<Slider />,或者另一个有复杂结构的<Grid>。是不是很神奇?
    还有我们上面进行的UI设计相对MFC来说繁琐很多,但是也要强大很多。这主要表现在窗口的大小被改变时。一个MFC对话框程序,如果没有经过特别精心的设计的话,一旦窗口大小被拖动或者最大化,一坨控件还像原来一样分布,拥堵在左上角,唉……但是上面设计出的WPF的程序就不会,控件仍然会均匀分布在窗口中。(你可以自己试试看,如果觉得还是不够完美可以自己想想怎样再改动呢?)

    下面进入消息处理阶段了,如果还可以这样称呼的话。第一步要把Slider和TextBox中的内容关联起来。为了以下程序设计的方便,我们必须要先给各个控件起个名字。在第一行的Slider里面添加Name属性,叫它ColorSliderR好了!也就是说,在<Slider ... />中加入Name="ColorSliderR"
    同样的,我们给剩下各个slider起名叫做ColorSliderG/B/A。把那个Button称作MainButton。
    然后要调整Slider的属性,否则没有应用价值。在各个Slider的代码里加入Maximum="255" Minimum="0" Value="255"。这表示滑块到达最右边的时候表示255,最左边表示0,初始值在255。那么Slider的代码看起来应该是这样的:

    <Slider Grid.Column="1" Grid.Row="0" Margin="5" VerticalAlignment="Center" Maximum="255" Minimum="0" Value="255" Name="ColorSliderR"/>

    睁大眼睛啦!WPF神奇的地方又来啦!什么消息处理,这么麻烦,走开!不就是同步嘛,把TextBox和Slider绑上不就得了。好的。在4个<TextBox ... />中加入代码Text="{Binding Path=Value, ElementName=ColorSliderR}",注意ElementName的值要根据各个控件改动哦。这样就把两个控件Bind起来了。运行一下看看:

    成功啦!简单不?啧啧,还带小数点的,真牛X。注意,如果想要通过改变文本框的内容来改变滑块位置的话,需要在输入完毕后切换一下焦点,也就是随便点一下本窗口内的其他地方改动才会生效。
    真么快?都到第四步了。下面就要改变背景色啦。XAML固然强大,但光玩控件间的绑定没意思,咱辛辛苦苦学的for啊while啊不都没用了嘛。这下咱换种方式。把XAML和后台代码绑定起来。
    为了实现这个目标,先要做一个桥梁——在XAML和后台代码间沟通的桥梁。终于轮到C#上场了,人家都急死了。右击XAML设计界面,单击View Code打开Window1.xaml.cs。啊,终于看到熟悉的using了,激动死了激动死了。
    在public partial class Window1这个类的后面,也就是这个类的}的后面,相当于跟这个类并列的地位,不要搞错了啊,插入一个类,代码如下:

    复制代码
    public class SliderCommunicator: INotifyPropertyChanged
    { // INotifyPropertyChanged Members
      public event PropertyChangedEventHandler PropertyChanged;
      protected void Notify(string propName)
      {
        if (this.PropertyChanged != null)
        {
         PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
      }
      int sliderValue = 255;
      public int SliderValue
      {
        get { return sliderValue; }
        set {
            sliderValue = value;
            Notify("SliderValue");
           }
          }
       }
    复制代码

    学过C#的对这个应该很熟悉,标准的事件处理方法。大意就是这个类里面有一个属性SliderValue。它一旦被更改了就会大叫:老大我被人动啦!然后——当然很多人根本不睬他,只有他的老大听到了就会过来看看并作出相关操作。这是C#针对消息处理作出的语言内部的支持。

    还有,不要忘了在最前面那一坨using的最后插入一句

    using System.ComponentModel;

    这是为了提供对事件处理的支持。

    有了这个类,桥架起来了,绑定就好办了。当然一个控件应该是和代码中的一个对象绑定而不是和一个类绑定,所以叫你有面向对象程序设计基础呢,否则对象啊类啊还不把你绕昏掉。对象自然只能在Window1类中定义。好的,在类中(具体位置随便在哪,只要这个类里面就好)加入

    SliderCommunicator sliderCR, sliderCG, sliderCB, sliderCA;

    然后搞个函数把他们初始化一下,整个Window1类看起来应该是这样的:

    复制代码
    public partial class Window1 : Window
    {
      SliderCommunicator sliderCR, sliderCG, sliderCB, sliderCA;
      public Window1()
      {
        InitializeComponent();
      }
      void InitDataBinding()
      {
        sliderCR = new SliderCommunicator();
        sliderCG = new SliderCommunicator();
        sliderCB = new SliderCommunicator();
        sliderCA = new SliderCommunicator();
      }
    }
    复制代码

    嗯嗯,很好,下面我们就可以把XAML和C#绑起来了。两步走,第一步,改改InitDataBinding函数,改成这样:

    复制代码
    void InitDataBinding()
    {
      sliderCR = new SliderCommunicator();
      ColorSliderR.DataContext = sliderCR;
      sliderCG = new SliderCommunicator();
      ColorSliderG.DataContext = sliderCG;
      sliderCB = new SliderCommunicator();
      ColorSliderB.DataContext = sliderCB;
      sliderCA = new SliderCommunicator();
      ColorSliderA.DataContext = sliderCA;
    }
    复制代码

    意思就是把每个Slider控件和相应的对象绑起来。

    第二步,回到XAML设计界面,在每一个<Slider ... />里把原来的Value="255"改成Value="{Binding Path=SliderValue}"
    这是更进一步具体地说,把这个Slider的Value属性和相应的那个对象的SliderValue绑定起来。
    好吧现在看看发生了什么事情呢。当Slider的滑块一被拖动的时候,WPF就会自动更新绑在一起的SliderCommunicator对象的Value属性,然后它就会大叫起来老大我被人动啦!但是现在还没人理他呀,没用呢。没关系,我们给他造出一个老大来。
    首先在Window1中定义函数

    复制代码
    void ChangeMainButtonColor(object sender, PropertyChangedEventArgs e)
    {
      SolidColorBrush NewColor = new SolidColorBrush();
      NewColor.Color = Color.FromArgb((byte)sliderCA.SliderValue, (byte)sliderCR.SliderValue, (byte)sliderCG.SliderValue, (byte)sliderCB.SliderValue);
      MainButton.Background = NewColor;
    }
    复制代码

    还记得那个Button其实叫做MainButton吗?这个函数就是改变Button背景值的。下面让它做个实实在在的老大。

    在InitDataBinding的最后部分加入语句

    复制代码
    sliderCR.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
    sliderCG.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
    sliderCB.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
    sliderCA.PropertyChanged += new PropertyChangedEventHandler(ChangeMainButtonColor);
    复制代码

    好了。现在SliderCommunicator一叫Button就会跑过来,然后把自己的背景改掉了。大功告成!运行看看:

  • 相关阅读:
    SLAB
    /proc/vmstat 详解
    swap空间可以有效缓解内存压力
    内存问题排查手段及相关文件介绍
    buddyinfo 内存碎片数据采集
    取得Linux系统的各种统计信息
    HTML的常用总结
    采用jquery同django实现ajax通信
    Django的quarySet
    Django-MySQL数据库使用01
  • 原文地址:https://www.cnblogs.com/masonlu/p/5262132.html
Copyright © 2020-2023  润新知