Как мне получить состояние переключателей внутри списка для привязки данных?
Следуя шаблону MVVM, у меня есть список, содержащий переключатели, состояние которых привязано к логическому свойству в списке элементов модели представления. У меня есть логика, которая вносит изменения в модель представления, но я не могу заставить пользовательский интерфейс распознать эти изменения.
Я нашел варианты этой проблемы в интернете, но не могу найти ничего столь же простого, как мой пример. Я не хочу чрезмерно усложнять код, поэтому надеюсь, что есть простое решение этой проблемы.
Мой реальный код слишком велик для публикации, но мне удалось построить следующий минимальный пример, который показывает то же самое поведение.
Мой XAML:
<Window x:Class="WpfApplication2.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:WpfApplication2" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Control.Resources> <ResourceDictionary> <DataTemplate x:Key="ProgressTrackingDataTemplate"> <Grid Margin="0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="{Binding Name}" Margin="0" Padding="2,2,2,2"/> <Viewbox Grid.Row="0" Grid.Column="1" Height="20"> <RadioButton IsChecked="{Binding State,Mode=TwoWay}"/> </Viewbox> </Grid> </DataTemplate> <Style x:Key="ProgressTrackingListBoxItemStyle" TargetType="ListBoxItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="Focusable" Value="False"/> </Style> </ResourceDictionary> </Control.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="30"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> </Grid.ColumnDefinitions> <ListView Grid.Row="0" Grid.Column="0" ItemsSource="{Binding ProgressValues}" ItemTemplate="{StaticResource ProgressTrackingDataTemplate}" ItemContainerStyle="{StaticResource ProgressTrackingListBoxItemStyle}"/> <Button Grid.Row="1" Grid.Column="0" Content="Change selected item" Click="Button_Click"/> </Grid> </Window>
Код-за:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = _myViewModel; } private void Button_Click( object sender, RoutedEventArgs e ) { _myViewModel.ChangeSelectedItem(); } private MyViewModel _myViewModel = new MyViewModel(); }
Модель представления:
using System.Collections.Generic; using System.ComponentModel; namespace WpfApplication2 { public class ProgressValue { public string Name { get; set; } = ""; public bool State { get; set; } = false; } public class MyViewModel : INotifyPropertyChanged { public MyViewModel() { _progressValues[ _selectedItemIndex ].State = true; } public event PropertyChangedEventHandler PropertyChanged; public List<ProgressValue> ProgressValues { get { return _progressValues; } } public void ChangeSelectedItem() { _selectedItemIndex++; if( _selectedItemIndex == _progressValues.Count ) _selectedItemIndex = 0; foreach( var progressValue in _progressValues ) progressValue.State = false; _progressValues[ _selectedItemIndex ].State = true; PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( nameof(ProgressValues) ) ); } private int _selectedItemIndex = 0; private List<ProgressValue> _progressValues = new List<ProgressValue>() { new ProgressValue() { Name = "Not Started", State = false }, new ProgressValue() { Name = "Underway", State = false }, new ProgressValue() { Name = "Completed", State = false }, new ProgressValue() { Name = "Invoiced", State = false } }; } }
Обратите внимание, что первоначальный выбор, который я выполняю в конструкторе модели представления, отражается в пользовательском интерфейсе, что подразумевает, что должен быть способ заставить это работать.
Любая помощь будет очень признательна.
Добрые пожелания ~ Патрик
Что я уже пробовал:
Я пробовал иметь переключатели в группе и не иметь их в группе.
Я пробовал различные способы поднять
PropertyChanged
событие, включающее передачу пустой строки в PropertyChangedEventArgs
, который, как я думал, был способом сказать пользовательскому интерфейсу, чтобы он пересмотрел все привязки?
Richard Deeming
Я подозреваю, что ваш ProgressValue
класс также нужно будет реализовать INotifyPropertyChanged
, и поднять PropertyChanged
событие, когда State
изменение свойства.
Patrick Skelton
Вы, сэр, настоящая звезда! Я просто не подумал об этом. Работает удовольствие (и сэкономил мне часы над ужасными альтернативами, которые я рассматривал). Спасибо!
Я бы принял это как ответ, но я не знаю, как сделать это с комментарием.
Richard Deeming
Тогда я отправлю его в качестве ответа! :)