(WPF) 再议binding:点击User Control时,User Control变换颜色或做其他的处理。

时间:2022-03-22 10:39:09

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, , new Point(,))
{
} 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=""
Width="">
<Grid>
<Grid HorizontalAlignment="Left"
Height=""
Margin="51,38,0,0"
VerticalAlignment="Top"
Width="">
<WrapPanel x:Name="wpBalls"
HorizontalAlignment="Left"
Height=""
VerticalAlignment="Top"
Width="">
<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, , new Point(,)); 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

(待续)