事件驱动是GUI开发的经典方案,但是事件驱动不符合程序的本质,数据+算法。
正是有了数据绑定,数据驱动UI才真正的实现了。在事件处理中,修改数据,提前跟数据绑定的控件不需要额外处理了,只要提前绑定了数据,控件的行为就会自然的改变。
控件展示数据并且响应用户的操作。WPF 强调数据驱动UI,实际上达到的效果就是非常
容易的扩展控件的外观和功能。
MainWindow:
public partial class MainWindow : Window,INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;
private bool state; public bool State { get { return state; } set { state = value; if (this.PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("State")); } } }
public MainWindow() { InitializeComponent(); State = false;
BindingOperations.SetBinding(Start, Button.IsEnabledProperty, new Binding() { Source = this,Path = new PropertyPath("State"), Converter = new InverseBooleanConverter() });
BindingOperations.SetBinding(End, Button.IsEnabledProperty, new Binding() { Source = this, Path = new PropertyPath("State") });
BindingOperations.SetBinding(S_State, StatusBarItem.ContentProperty, new Binding() { Source = this, Path = new PropertyPath("State"), Converter = new StateTextConverter() });
}
private void Start_Click(object sender, RoutedEventArgs e) { State = true; }
private void End_Click(object sender, RoutedEventArgs e) { State = false; } |
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" xmlns:test="clr-namespace:System.Data;assembly=System.Data" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.Resources>
</Window.Resources> <Grid> <StackPanel> <Button Content="启动" x:Name="Start" Click="Start_Click" Width="100" Height="30"></Button> <Button Content="停止" x:Name="End" Click="End_Click" Width="100" Height="30" Margin="10"></Button> <StatusBar > <StatusBarItem Content="" x:Name="S_State"></StatusBarItem> </StatusBar> </StackPanel>
</Grid> </Window>
|
InverseBooleanConverter:
[ValueConversion(typeof(bool), typeof(bool))] public class InverseBooleanConverter : IValueConverter { #region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (targetType != typeof(bool)) throw new InvalidOperationException("The target must be a boolean");
return !(bool)value; }
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); }
#endregion } |
StateTextConverter:
[ValueConversion(typeof(bool), typeof(object))] public class StateTextConverter : IValueConverter { #region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (targetType != typeof(object)) throw new InvalidOperationException("The target must be a object");
if ((bool)value) { return "运行中..."; } else { return "停止中..."; } }
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); }
#endregion } |
最终效果:
其实这只是一个简单的效果,也许直接设置控件的属性更加的简单,代码都少很多。
但是这里主要的学习的是解决问题的思路,我把程序运行的状态设置到State属性上,
State使用数据绑定通知到按钮的状态和状态栏的文字。
在数据绑定的时候,有个转换器对象规定怎么处理数据的,处理后的数据直达控件,我们不需要直接设置控件了。