湖边的白杨树

探索是一种乐趣

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

Binding 是前台UI(显示层)和后台代码(数据层)的桥梁。理论上当后台的数据变动时,显示的数据或样式应该随之而变。这些是动态的。

对于Binding的设置可以在前台Xaml,也可以在后台Code里面定义,但是既然Xaml可以做很多事情,那么所有对UI的操作我们都可以交给它。

 其实,WPF的本身是一种数据驱动UI的设计模式,使用了MVVM(Model-View-ViewModel)的模式。

 

以下是绑定的基本思路:

目标(依赖对象(依赖属性))  <=====Binding =====> 源(CLR 对象(属性))

 

实验1

设计一个圆形的球,包括红球和篮球,有编号。初始状态为灰色,当选中时,红球颜色显示为红,篮球颜色显示为蓝。再次选中时,颜色返回为初始状态(灰色)

另外,当球被选中时,可以处理一下数据,如读取编号。

 

思路:

1.首先设计一个Ball 类 包含了IsSelected, Type, Index 属性,并继承了INotifyPropertyChanged接口,当IsSelected属性变更的时候,产生了PropertyChanged的Event。

2.创建了一个BallControl的 User Control (WPF). 

3.bindingBall类到BallControl上。对binding做一些设定,从而实现实验1的需求。

 

实现:

1. 新建Ball类. 实现INotifyPropertyChanged 接口,当属性IsSelected值变化的时候,调用PropertyChanged event

    public class Ball : INotifyPropertyChanged
    {
        /// <summary>
        /// Fired whenever a property changes.  Required for
        /// INotifyPropertyChanged interface.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        private bool selected; 

        private BallType type;

        private int index;

        private Point size;

        public Ball()
            :this(false, BallType.gray, 0, new Point(40,40))
        {
        }

        public Ball(bool ballIsSelected, BallType ballType, int ballIndex, Point ballSize)
        {
            this.selected = ballIsSelected; 
            this.type = ballType; 
            this.index = ballIndex; 
            this.size = ballSize; 
        }

        public bool IsSelected
        {
            get
            {
                return this.selected; 
            }

            set
            {
                if (value != this.selected)
                {
                    this.selected = value;
                    if (this.PropertyChanged != null)
                    {
                        this.PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
                    }
                }
            }
        }

        public BallType Type
        {
            get
            {
                return this.type;
            }
        }

        public int Index
        {
            get
            {
                return this.index;
            }
        }
    }

    public enum BallType
    {
        gray,

        Red,

        Blue,
    }

 

2. 新建一个User Control (WPF), 名为BallControl,依次放入Grid, Border, Ellipse, TextBlock 控件. 完成 UI 布局。

在后台为鼠标点击动作添加一个Event,当Ball控件被点击选择的时候,会做一些需要的处理。 

<UserControl x:Name="myBallControl"
             x:Class="BallSelection.BallControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:BallSelection"
             mc:Ignorable="d"
             Height="100"
             Width="100">
    <Grid Height="100"
          Width="100"
          VerticalAlignment="Top"
          MouseDown="UIElement_OnMouseDown">
        <Border BorderBrush="Black"
                BorderThickness="1"
                HorizontalAlignment="Left"
                Width="100"
                Height="100"
                RenderTransformOrigin="0.481,0.183">
            <Ellipse x:Name="circle"
                     Stroke="Black"
                     Margin="6,6,6,6">
            </Ellipse>
        </Border>
        <TextBlock x:Name="tbIndex"
                   Text="0"
                   FontSize="58"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center" />
    </Grid>
</UserControl>
    /// <summary>
    /// Interaction logic for BallControl.xaml
    /// </summary>
    public partial class BallControl : UserControl
    {
        public event EventHandler<EventArgs> SelectionChanged;

        public BallControl()
        {
            InitializeComponent();
        }

        private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (this.SelectionChanged != null)
            {
                this.SelectionChanged(this, EventArgs.Empty);
            }
        }    
    }

 

4. 设计MainWindow的UI,依次放入Grid,WrapStack,和BallControl。

<Window x:Class="BallSelection.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BallSelection"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Grid>
        <Grid HorizontalAlignment="Left"
              Height="227"
              Margin="51,38,0,0"
              VerticalAlignment="Top"
              Width="396">
            <WrapPanel x:Name="wpBalls"
                       HorizontalAlignment="Left"
                       Height="227"
                       VerticalAlignment="Top"
                       Width="386">
                <local:BallControl x:Name="redBallControl" />
                <local:BallControl x:Name="blueBallControl" />
            </WrapPanel>
        </Grid>
    </Grid>
</Window>

 

5. 进行Binding, 有两种方法:一种是在后台Code里面进行binding, 另外一种是在前台Xaml里面进行binding。

方法一:在后台Code里面进行binding

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.InitializeBalls(); 
        }

        private void InitializeBalls()
        {
            Ball redBall = new Ball(false, BallType.Red, 1, new Point(50,50));

            Binding bindingIndex = new Binding()
            {
                Source = redBall,
                Path = new PropertyPath("Index")
            };

            // this is  equal to: this.blueBallControl.tbIndex.SetBinding(TextBlock.TextProperty, bindingIndex);
            BindingOperations.SetBinding(this.redBallControl.tbIndex, TextBlock.TextProperty, bindingIndex); 

            Binding bindingSelect = new Binding()
            {
                Source = redBall,
                Path = new PropertyPath("IsSelected"),
                Converter = new BooleanToColor(),
            };

            BindingOperations.SetBinding(this.redBallControl.circle, Ellipse.FillProperty, bindingSelect);

            // Handle selection changed event. 
            this.redBallControl.SelectionChanged += ((s, e) =>
            {
                redBall.IsSelected = !redBall.IsSelected;
                MessageBox.Show(string.Format("BallControl Index {0} is selected.\t\n. Ball Type:{1}, Index:{2}, IsSelected:{3}.", this.redBallControl.tbIndex.Text, redBall.Type.ToString(), redBall.Index, redBall.IsSelected));
            }); 
        }

    }

这里在binding的过程中,当ball control被选中的时候, 颜色会自动进行转换,所以需要一个Converter。

    public class BooleanToColor : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType != typeof(Brush))
                throw new InvalidOperationException("The target must be a Brush");

            if (value == null)
                return Brushes.Gray;

            return (bool)value ? Brushes.Red : Brushes.Gray;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }

方法二:在前台Xaml里面进行binding

(待续)

posted on 2014-06-29 19:33  fdyang  阅读(875)  评论(0编辑  收藏  举报