Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF绑定未更新XAML,但调用了PropertyChanged_C#_.net_Wpf_Mvvm_Synchronization - Fatal编程技术网

C# WPF绑定未更新XAML,但调用了PropertyChanged

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

我正在尝试将XAML中WPF UI元素的可见性绑定到视图模型的属性(
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