WPF 提供诸如属性更改通知、依赖属性和绑定等功能。
所以 WPF 中的良好做法是使用 PresentationModel-View 模式或 MVC 模式,而不是直接访问控件。
您的表示模型(或控制器)必须处理所有业务逻辑,并且视图仅反映模型的实际状态。
在您的案例中,模型如下所示:
public class SampleModel : ObservableObject
{
private bool? _isFirstChecked;
public bool? IsFirstChecked
{
get
{
return this._isFirstChecked;
}
set
{
if (this._isFirstChecked != value)
{
this._isFirstChecked = value;
this.OnPropertyChanged("IsFirstChecked");
}
}
}
private int _maxWeight;
public int MaxWeight
{
get
{
return this._maxWeight;
}
set
{
if (this._maxWeight != value)
{
this._maxWeight = value;
this.OnPropertyChanged("MaxWeight");
}
}
}
public IEnumerable<int> ComboBoxItems
{
get
{
yield return 123;
yield return 567;
yield return 999;
yield return 567;
yield return 1999;
yield return 5767;
yield return 9990;
}
}
}
由于我们必须通过属性更改事件通知视图,我们添加了 Observable 类,它实现了这个逻辑:
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var safePropertyChanged = this.PropertyChanged;
if (safePropertyChanged != null)
{
safePropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
所以,现在我们有了带有必要属性声明的表示模型,让我们看看:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self ="clr-namespace:Test"
Title="MainWindow"
Height="350" Width="525">
<Window.Resources>
<self:NullableBoolToStringConvreter x:Key="nullableBoolToStringConverter" />
</Window.Resources>
<Grid>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label VerticalAlignment="Center">IsFirstChecked:</Label>
<CheckBox VerticalAlignment="Center"
IsChecked="{Binding Path=IsFirstChecked}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label VerticalAlignment="Center">Max Weight:</Label>
<ComboBox ItemsSource="{Binding Path=ComboBoxItems}"
VerticalAlignment="Center"
SelectedValue="{Binding Path=MaxWeight}">
</ComboBox>
</StackPanel>
<TextBox Text="{Binding Path=MaxWeight}" />
<TextBox Text="{Binding Path=IsFirstChecked, Converter={StaticResource nullableBoolToStringConverter}}"/>
<Button Click="Button_Click" Content="Reset combo box to 999 and checkbox to null"/>
</StackPanel>
</Grid>
我们还要修改后面的这个xaml代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var model = new SampleModel();
model.MaxWeight = 5767;
this.Model = model;
}
public SampleModel Model
{
get
{
return (SampleModel)this.DataContext;
}
set
{
this.DataContext = value;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Model.MaxWeight = 999;
this.Model.IsFirstChecked = null;
}
}
如您所见,我们在 MainWindow 构造函数中创建 SampleModel 实例,设置其属性并将模型实例设置为视图的 DataContext。
DataContext 更改后,WPF 内部机制开始绑定过程。例如,对于组合框控件,它提取模型属性 ComboBoxItems 并创建项目容器。然后提取属性 MaxValue 并将其绑定到 SelectedValue,即组合框选择将指向值“5767”。
出于演示目的,我放置了两个文本框,它们显示“MaxWeight”和“IsFirstChecked”属性的实际值。默认绑定实现在 null 值上显示空字符串,因此我们必须添加适当的转换器:
public class NullableBoolToStringConvreter : IValueConverter
{
private static readonly string _NullString = "Null";
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value == null ? NullableBoolToStringConvreter._NullString : value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
您可以测试应用程序并确保 UI 控件状态的更改自动反映在模型中。另一方面,单击按钮会将模型属性重置为定义的值,并且 UI 会立即对其做出反应。
因此,使用 WPF,您无需访问控件。 XAML 和 InitializeComponent() 保证您创建了所有控件。
关于检查:
control.IsChecked.HasValue && (bool)control.IsChecked
如前所述,您可以使用表达式
model.IsFirstChecked ?? false
或扩展方法:
public static class BooleanNullableExtensions
{
public static bool IsTrue(this Nullable<bool> value)
{
return value.HasValue && value.Value;
}
}