如何将列表中的单选按钮状态设置为数据绑定? [英] How do I get the state of radio buttons inside a list to data-bind?
问题描述
遵循MVVM模式,我有一个包含单选按钮的列表,其状态绑定到视图模型中项目列表中的布尔属性。我有逻辑在视图模型中进行更改,但我无法让UI识别这些更改。
我在网上找到了这个问题的变种但是找不到像我的例子一样简单。我不想让代码过于复杂,所以我希望有一个简单的解决方案。
我的实际代码太大而无法发布,但我设法构建了以下显示相同行为的最小示例。
我的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高度=350宽度=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 =0Grid.Column =0Content ={Binding Name}Margin =0Padding =2,2,2,2/>
< Viewbox Grid.Row =0Grid.Column =1Height =20>
< RadioButton IsChecked ={Binding State,Mode = TwoWay}/>
< / Viewbox>
< / Grid>
< / DataTemplate>
< Style x:Key =ProgressTrackingListBoxItemStyleTargetType =ListBoxItem>
< Setter Property =HorizontalContentAlignmentValue =Stretch/>
< Setter Property =FocusableValue =False/>
< / Style>
< / ResourceDictionary>
< /Control.Resources>
< Grid>
< Grid.RowDefinitions>
< RowDefinition />
< RowDefinition Height =30/>
< /Grid.RowDefinitions>
< Grid.ColumnDefinitions>
< ColumnDefinition />
< /Grid.ColumnDefinitions>
< ListView Grid.Row =0Grid.Column =0
ItemsSource ={Binding ProgressValues}
ItemTemplate ={StaticResource ProgressTrackingDataTemplate}
ItemContainerStyle ={StaticResource ProgressTrackingListBoxItemStyle}/>
< Button Grid.Row =1Grid.Column =0Content =Change selected itemClick =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();
}
视图型号:
< pre lang =c#> 使用 System.Collections.Generic;
使用 System.ComponentModel;
命名空间 WpfApplication2
{
public class ProgressValue
{
public string 名称{获取; set ; } = ;
public bool 状态{获取; set ; } = false ;
}
public class MyViewModel:INotifyPropertyChanged
{
public MyViewModel()
{
_progressValues [_selectedItemIndex] .State = true 跨度>;
}
public event PropertyChangedEventHandler PropertyChanged;
public 列表< 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 列表< ProgressValue> _progressValues = new 列表< ProgressValue>()
{
new ProgressValue() {Name = 未开始,State = false },
new ProgressValue(){Name = 正在进行,State = false },
new ProgressValue(){Name = 已完成,State = false },
new ProgressValue(){Name = 已开票,状态= false }
};
}
}
请注意,我在视图模型的构造函数中执行的初始选择是反映在用户界面中,这意味着必须有办法让这个工作。
任何帮助都将非常感激。
< br $>
亲切的愿望~Patrick
我尝试过:
我尝试过在一个小组中使用单选按钮但没有将它们放在一个小组中。
我尝试了各种方法来提高 PropertyChanged
事件,包括在 PropertyChangedEventArgs
中传递一个空字符串,我认为这是一种告诉用户界面重新评估所有内容的方法绑定?如评论中所述,
ProgressValue
类需要实现 INotifyPropertyChanged
,并在州
属性更改时引发 PropertyChanged
事件。
public class ProgressValue:INotifyPropertyChanged
{
private bool _state;
公共事件PropertyChangedEventHandler PropertyChanged;
public string Name {get;组; } =;
public bool State
{
get
{
return _state;
}
设置
{
_state = value;
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(State)));
}
}
}
Following the MVVM pattern, I have a list that contains radio buttons, the state of which is bound to a boolean property in a list of items in the view-model. I have logic that makes changes in the view-model, but I cannot get the UI to recognise these changes.
I have found variations of this problem online but cannot find anything as simple as my example. I don't want to over-complicate the code, so I am hoping there is a simple solution to this.
My real code is way too big to post, but I have managed to construct the following minimal example that shows the same behaviour.
My 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>
The code-behind:
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();
}
The view-model:
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 }
};
}
}
Note that the initial selection that I perform in the constructor of the view-model is reflected in the UI, which implies there must be a way to get this working.
Any help would be very much appreciated.
Kind wishes ~ Patrick
What I have tried:
I have tried having the radio buttons in a group and not having them in a group.
I have tried various ways to raise the PropertyChanged
event, including passing an empty string in the PropertyChangedEventArgs
, which I thought was a way to tell the UI to re-evaluate all bindings?
As mentioned in the comments, theProgressValue
class needs to implementINotifyPropertyChanged
, and raise thePropertyChanged
event when theState
property changes.
public class ProgressValue : INotifyPropertyChanged { private bool _state; public event PropertyChangedEventHandler PropertyChanged; public string Name { get; set; } = ""; public bool State { get { return _state; } set { _state = value; PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( nameof(State) ) ); } } }
这篇关于如何将列表中的单选按钮状态设置为数据绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!