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;
}
}
Как вы можете видеть, мы создаем экземпляр SampleModel в конструкторе MainWindow, настраиваем его свойства и устанавливаем экземпляр модели как DataContext представления.
После изменения DataContext внутренний механизм WPF начинает процесс привязки. Например, для элемента управления combobox он извлекает свойство модели ComboBoxItems и создает контейнеры элементов. Затем извлекает свойство MaxValue и привязывает его к SelectedValue, то есть выделение в выпадающем списке будет указывать на значение «5767».
В целях демонстрации я поместил два текстовых поля, которые отображают фактическое значение свойств "MaxWeight" и "IsFirstChecked". Реализация привязки по умолчанию показывает пустые строки с нулевыми значениями, поэтому мы должны добавить соответствующий конвертер:
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();
}
}
Вы можете протестировать приложение и убедиться, что изменения состояния элементов управления пользовательского интерфейса автоматически отражаются в модели. С другой стороны, нажатие на кнопку сбрасывает свойства модели до определенных значений, и пользовательский интерфейс немедленно реагирует на это.
Так что с 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;
}
}