Даже после просмотра множества предложений решений я не могу заставить работать простую двухстороннюю привязку в xaml. У меня есть окно, dataContext и приложение. Проблема в том, что:
а) во время работы конструктора приложения окно (инициализированное и .Show
-ed в том же конструкторе) появляется, но вообще не обновляется, хотя я несколько раз переключаю значение флажка в своем коде C#;
б) когда конструктор приложения завершает работу, окно обновляется ровно один раз; Я настроил его так, что если я щелкну флажок в окне, обработчик событий в приложении (привязанный к уведомлению об изменении свойства DataContext) должен увеличить размер списка строк, который также отображается. Увеличение списка происходит корректно в коде, но не отражается в окне.
Обзор:
- пользовательский ввод в окне достигает кода С# приложения в порядке: я могу действовать при изменении флажка и т. д.
- обратное направление не работает: всякий раз, когда элементы в dataContext изменяются с помощью кода, окно не обновляется автоматически, даже если iNotifyProperty реализовано и выполняется.
Я ожидаю, что:
а) в то время как конструктор приложения запускается и переключает значение CheckBox, окно должно отражать изменения, устанавливая/снимая галочку в поле;
б) после завершения конструктора приложения, всякий раз, когда я переключаю CheckBox с FALSE на TRUE, к NameList
добавляется новая строка. Я ожидаю, что список в окне соответственно увеличится и автоматически покажет полное добавленное содержимое NameList
.
Наблюдения:
- Я пытаюсь убедиться, что DataContext в окне установлен перед вызовом
InitializeComponent
в окне. разницы особо нет к сожалению... - Я получаю единственную подсказку в VS в файле MainWindow.xaml: путь CheckBox, а также привязка ListBox
NameList
аннотируются с помощьюCannot resolve symbol due to unknown DataContext
Однако, когда конструктор приложения завершает работу, окно обновляется, и когда я нажимаю CheckBox, запускается правильное событие NotifyProperty. Это говорит мне о том, что привязки времени выполнения на самом деле должны работать ... по-видимому, только в одну сторону, а не в две стороны.
MainWindow.xaml:
<Window x:Class="StatisticsEvaluation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Vertical">
<CheckBox IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" Content="CheckBox" />
<ListBox ItemsSource="{Binding NameList, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock FontSize="18" FontFamily="Arial" Foreground="Black" Text="TextBlock" Visibility="Visible" />
</StackPanel>
</Grid>
MainWindow.xaml.cs:
namespace StatisticsEvaluation
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
}
}
}
Приложение и DataContext:
namespace StatisticsEvaluation
{
public class DataContextClass : INotifyPropertyChanged
{
private bool isChecked;
public bool IsChecked
{
get
{
return isChecked;
}
set
{
isChecked = value;
OnPropertyChanged("IsChecked");
}
}
private List<string> nameList;
public List<string> NameList
{
get
{
return nameList;
}
set
{
nameList = value;
OnPropertyChanged("NameList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private MainWindow MyWindow { get; set; }
private DataContextClass MyDataContext{ get; set; }
private void HandleDataContextPropertyChange(object sender, PropertyChangedEventArgs e)
{
// If the CheckBox was just toggled to TRUE, increase the NameList
// with an additional name and call OnPropertyChanged on it ...
// hoping that this would trigger a Window UI update - but no luck !
if ((e.PropertyName == "IsChecked") && MyDataContext.IsChecked)
{
var randomProvider = new Random();
MyDataContext.NameList.Add(randomProvider.Next().ToString());
MyDataContext.OnPropertyChanged("NameList");
}
}
public App()
{
MyDataContext = new DataContextClass();
MyDataContext.PropertyChanged += HandleDataContextPropertyChange;
MyWindow = new MainWindow {DataContext = MyDataContext};
MyWindow.InitializeComponent();
MyWindow.Show();
MyDataContext.NameList = new List<string>();
MyDataContext.NameList.Add("FirstName");
MyDataContext.NameList.Add("SecondName");
MyDataContext.NameList.Add("ThirdName");
MyDataContext.IsChecked = true;
Thread.Sleep(3000);
MyDataContext.IsChecked = false;
Thread.Sleep(3000);
MyDataContext.IsChecked = true;
}
}
}
Когда я запускаю приложение, появляется следующее окно, как только конструктор приложения достигает .Show
:
Как только конструктор приложения завершает работу, окно обновляется один раз, но никогда больше после этого, независимо от того, сколько строк добавлено к NameList
:
Любые идеи, почему моя двусторонняя привязка работает только в одном направлении?
MyDataContext
вещи вApp
и просто создать модель представления в конструкторе MainWindow или что-то в этом роде. Кроме того, всегда используйтеObservableCollection<T>
для коллекций, которые будут привязаны к элементам управления в WPF. Не используйте Список. Он не вызывает событий при изменении его содержимого. - person 15ee8f99-57ff-4f92-890c-b56153   schedule 23.09.2016ItemsSource="{Binding NameList, Mode=TwoWay}"
не имеет смысла. ItemsControl никогда не изменяет свое свойствоItemsSource
, поэтому параметрMode=TwoWay
никогда не имеет никакого эффекта. Кроме того,MyDataContext.OnPropertyChanged("NameList");
молча игнорируется, потому что экземпляр NameList не изменяется. Поэтому используйте ObservableCollection. - person Clemens   schedule 23.09.2016