Привязать уже сфомированный List к ListView WPF
Подскажите пожалуйста, как привязать коллекцию, которая у меня сформирована в другом классе, чтобы при нажатии на кнопку заполнился ListView, не используя в основном коде программы свойство ItemSource, то есть чтобы через привязку это делалось автоматически, или какие вообще пути решения есть. Везде по-разному пишут. Хотелось точно понять как это делать. Спасибо!
P.S. сейчас ListView заполняется, но используется при этом в коде свойство ItemSource
XAML
<Grid>
<StackPanel Orientation="Vertical" Margin="5">
<Button x:Name="Go" Content="Поехали" Height="25" Margin="5" Click="Go_Click"/>
<ListView Margin="5" Height="100" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="Stolb1" Width="100"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Grid>
Код в основной части:
public partial class MainWindow : Window
{
public ObservableCollection<string> mylist { get; set; }
public MainWindow()
{
InitializeComponent();
}
private void Go_Click(object sender, RoutedEventArgs e)
{
ListUp listUp = new ListUp();
ListView.ItemsSource = listUp.Numbers;
}
private class ListUp : INotifyPropertyChanged
{
public List<string> Numbers = new List<string> {"1", "2","3" };
public event PropertyChangedEventHandler PropertyChanged;
}
}
Ответы (1 шт):
У контролов есть свойство DataContext все биндинги работают относительно того объекта, на который этот DataContext указывает.
С точки зрения подхода MVVM ваша задача решается так:
1) Создайте класс MainViewModel, он будет содержать свойства для биндингов главного окна.
public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> _myList;
public ObservableCollection<string> MyList
{
get => _myList;
set
{
_myList = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
2) Подключите его к окну, самый простой (но не лучший) способ - сделать это в конструкторе класса окна:
private MainViewModel VM;
public MainWindow()
{
InitializeComponent();
VM = new MainViewModel();
this.DataContext = VM;
}
К свойствам VM из класса окна можно обращаться например вот так:
string str = VM.MyList[0];
3) Задайте привязку в xaml
<ListView Margin="5" Height="100" ItemsSource="{Binding MyList}">
Ну и (чтобы меня тут не побили другие читатели) стоит учитывать, что MVVM - это когда в классе окна или контрола работа с данными не производится. У меня даже в больших проектах в классе MainWindow пусто. Даже ни одного обработчика событий. Взаимодействие интерфейса и кода происходит только через биндинги, и никак иначе. Вам просто будет без надобности обращаться к контролам явно, так как они сами будут себя обновлять через биндинги.
Что же делать, когда нажата кнопка в MVVM, если не использовать обработчики события? Использовать команды!
Вот класс, позволяющий удобно использовать команды, просто положите его в проект (очень давно взял его здесь).
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
}
А использовать его можно, добавив в MainViewModel вот такой код
private ICommand _myCommand;
public ICommand MyCommand => _myCommand ?? (_myCommand = new RelayCommand(parameter =>
{
MyList = new ObservableCollection<string>() { "Элемент 1", "Элемент 2", "Элемент 3" };
MyList.Add("Элемент 4");
}));
В разметке тоже ничего сложного
<Button Content="Поехали" Height="25" Margin="5" Command="{Binding MyCommand}"/>