C# WPF绑定未更新XAML,但调用了PropertyChanged
我正在尝试将XAML中WPF UI元素的可见性绑定到视图模型的属性(C# WPF绑定未更新XAML,但调用了PropertyChanged,c#,.net,wpf,mvvm,synchronization,C#,.net,Wpf,Mvvm,Synchronization,我正在尝试将XAML中WPF UI元素的可见性绑定到视图模型的属性(MainViewModel.DisplayPopup),该属性是从另一个视图模型(ContactViewModel)的属性更新而来的,该视图模型是此类(MainViewModel)的属性。BaseViewModel类扩展了INotifyPropertyChanged,并使用一个Nuget包在每个属性的setter内自动调用PropertyChanged事件。 这是我的视图模型代码: public class MainViewMo
MainViewModel.DisplayPopup
),该属性是从另一个视图模型(ContactViewModel
)的属性更新而来的,该视图模型是此类(MainViewModel
)的属性。BaseViewModel
类扩展了INotifyPropertyChanged
,并使用一个Nuget包在每个属性的setter内自动调用PropertyChanged事件。
这是我的视图模型代码:
public class MainViewModel : BaseViewModel
{
public ObservableCollection<ContactViewModel> TankItems {get; set; }
public bool DisplayPopup
{
get => TankItems.Any(contact => contact.DisplayPopup);
}
public MainViewModel() : base()
{
TankItems = new ObservableCollection<ContactViewModel>();
TankItems.Add(new ContactViewModel());
TankItems.Add(new ContactViewModel());
}
}
public class ContactViewModel : BaseViewModel
{
private bool _isSelected = false;
public bool DisplayPopup {get; set; } = false;
public bool IsSelected {get => _isSelected; set { _isSelected = value; DisplayPopup = value;
}
在储罐项目中绑定选定状态
代码中存在多个问题。让我们从ContactViewModel
开始
public bool IsSelected {get => _isSelected; set { _isSelected = value; DisplayPopup = value;
displayppopup
属性是冗余的,因为它的状态与IsSelected
相同,请将其删除
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.Style>
更新显示弹出窗口属性
如果选择了任何项目,则需要将MainViewModel
上的DisplayPopup
设置为true
。上面的项目容器样式将设置您的ContactViewModel
的IsSelected
属性,但不会自动触发MainViewModel
中的displayppopup
属性更改。因此,“文本”绑定永远不会更新其值
要解决此问题,请将MainViewModel
中的DisplayPopup
属性设置为一个简单的get set属性。你不需要计算它。创建第二个属性以绑定MainViewModel
中ListBox
的SelectedItem
。当选择更改时,将设置此属性
public bool DisplayPopup { get; set; }
public ContactViewModel SelectedTankItem { get; set; }
另外,创建一个名为OnSelectedTankItemChanged
的方法,根据SelectedTankItem
设置DisplayPopup
属性。当SelectedTankItem
更改时,Fody框架将自动调用此方法
public void OnSelectedTankItemChanged()
{
DisplayPopup = SelectedTankItem != null;
}
然后将列表框上的SelectedItem
绑定到SelectedTankItem
<ListBox Grid.Column="0" ItemsSource="{Binding TankItems}" SelectedItem="{Binding SelectedTankItem}">
<!-- ...other code. -->
</ListBox>
在储罐项目中绑定选定状态
代码中存在多个问题。让我们从ContactViewModel
开始
public bool IsSelected {get => _isSelected; set { _isSelected = value; DisplayPopup = value;
displayppopup
属性是冗余的,因为它的状态与IsSelected
相同,请将其删除
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.Style>
更新显示弹出窗口属性
如果选择了任何项目,则需要将MainViewModel
上的DisplayPopup
设置为true
。上面的项目容器样式将设置您的ContactViewModel
的IsSelected
属性,但不会自动触发MainViewModel
中的displayppopup
属性更改。因此,“文本”绑定永远不会更新其值
要解决此问题,请将MainViewModel
中的DisplayPopup
属性设置为一个简单的get set属性。你不需要计算它。创建第二个属性以绑定MainViewModel
中ListBox
的SelectedItem
。当选择更改时,将设置此属性
public bool DisplayPopup { get; set; }
public ContactViewModel SelectedTankItem { get; set; }
另外,创建一个名为OnSelectedTankItemChanged
的方法,根据SelectedTankItem
设置DisplayPopup
属性。当SelectedTankItem
更改时,Fody框架将自动调用此方法
public void OnSelectedTankItemChanged()
{
DisplayPopup = SelectedTankItem != null;
}
然后将列表框上的SelectedItem
绑定到SelectedTankItem
<ListBox Grid.Column="0" ItemsSource="{Binding TankItems}" SelectedItem="{Binding SelectedTankItem}">
<!-- ...other code. -->
</ListBox>
绑定到DisplayPopup
的原因是该属性是一个计算属性,因此不会更新。计算属性缺少setter,因此从不引发INotifyPropertyChanged.PropertyChanged
。数据绑定侦听此事件。因此,displaypop.Get
只被调用一次(在绑定初始化时)
要解决此问题,您可以让MainViewModel
侦听ContactViewModel
项目的PropertyChanged
事件,或者您似乎对所选项目感兴趣,只需绑定列表框。选择editem
并更改MainViewModel。在更改时显示弹出窗口
public bool DisplayPopup { get; set; }
public ContactViewModel SelectedTankItem { get; set; }
为了简单起见,我推荐第二种解决方案
请注意,为了使ListBox.IsSelected
绑定工作,必须设置ListBox.ItemContainerStyle
和目标ListBoxItem
,而不是ListBox
:
MainViewModel.cs
public class MainViewModel : BaseViewModel
{
public ObservableCollection<ContactViewModel> TankItems { get; set; }
private ContactViewModel selectedTankItem;
public ContactViewModel SelectedTankItem
{
get => this.selectedTankItem;
set
{
this.selectedTankItem = value;
OnPropertyChanged(nameof(this.SelectedTankItem));
this.DisplayPopup = this.SelectedTankItem != null;
}
// Raises INotifyPropertyChanged.PropertyChanged
public bool DisplayPopup { get; set; }
public MainViewModel() : base()
{
TankItems = new ObservableCollection<ContactViewModel>()
{
new ContactViewModel(),
new ContactViewModel()
};
}
}
public类MainViewModel:BaseViewModel
{
公共ObservableCollection项目{get;set;}
private ContactViewModel selectedTankItem;
公共联系人视图模型选定的银行项目
{
get=>this.selectedTankItem;
设置
{
this.selectedTankItem=值;
OnPropertyChanged(name of(this.SelectedTankItem));
this.DisplayPopup=this.SelectedTankItem!=null;
}
//引发INotifyPropertyChanged.PropertyChanged
公共bool显示弹出窗口{get;set;}
public MainViewModel():base()
{
TankItems=新的ObservableCollection()
{
新建ContactViewModel(),
新的ContactViewModel()
};
}
}
main window.xaml
<ListBox ItemsSource="{Binding TankItems}"
SelectedItem="{Binding SelectedTankItem}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected"
Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type ContactViewModel}">
<StackPanel>
<TextBlock Text="Test" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border>
<TextBlock Text="{Binding DisplayPopup}" />
</Border>
绑定到DisplayPopup
的原因是该属性是一个计算属性。计算属性缺少setter,因此从不引发INotifyPropertyChanged.PropertyChanged
。数据绑定侦听此事件。因此,DisplayPopup.Get
只调用一次(绑定初始化的时刻)
要解决此问题,您可以让MainViewModel
侦听ContactViewModel
项目的PropertyChanged
事件,或者您似乎对所选项目感兴趣,只需绑定列表框。SelectedItem
和c