如何将列表中的单选按钮状态设置为数据绑定? [英] How do I get the state of radio buttons inside a list to data-bind?

查看:89
本文介绍了如何将列表中的单选按钮状态设置为数据绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

遵循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 =Horizo​​ntalContentAlignmentValue =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, the ProgressValue class needs to implement INotifyPropertyChanged, and raise the PropertyChanged event when the State 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆