WPF 数据绑定:视图未从视图模型更新
WPF databinding: view not updating from viewmodel
我的 WPF 应用程序以一种奇怪的方式工作 - 一些绑定有效,其他无效。
我有以下情况:
一个文本框 - 用户提供一个 ID。基于此 ID 加载或创建对象。其他一些属性由来自 loaded/new 对象的值更新。
ID 文本框的绑定工作正常。但是,其他两个视图(any other)不是。
我的代码示例:
XAML:
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
<TextBlock Text="ID" FontFamily="Segoe UI Light" />
<TextBox x:Name="TB_PacientID" Width="100px" HorizontalAlignment="Left" Margin="5,0,0,0" Text="{Binding Path=PacientID}"/>
<TextBlock x:Name="TBL_NovyPacient" Text="nový pacient" Margin="5,0,0,0" Foreground="Green" FontWeight="Bold" Visibility="{Binding Path=IsNewPacient,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource BTVConverter}}"/>
</StackPanel>
<WrapPanel x:Name="WP_PacientData" Margin="-2,5,2,5" Visibility="{Binding PacientLoaded,Converter={StaticResource BTVConverter}}">
...
视图模型:
public int? PacientID
{
get
{
if (CurrentPacient == null)
return null;
return CurrentPacient.id;
}
set
{
if (value != null)
{
_pacient = App.instance.sessionData.serviceProxy.pacientById(value.Value);
if (_pacient == null)
{
CurrentPacient = new Pacient() { id = value.Value };
IsNewPacient = true;
}
else
{
CurrentPacient = _pacient;
}
OnPropertyChanged();
PacientLoaded = true;
}
}
}
// ...
public bool IsNewPacient
{
get{ return _isNewPacient; }
set
{
_isNewPacient = value;
OnPropertyChanged();
}
}
//...
public bool PacientLoaded
{
get{ return _pacientLoaded; }
set
{
_pacientLoaded = value;
OnPropertyChanged();
}
}
想法:
用户输入 ID,加载或创建对象并显示 WrapPanel。如果对象是新创建的,那么也会显示 TextBlock。
转换器工作正常(在另一个 window 中测试)。
当 window 加载时,绑定建立良好(如果我在 ctor 中设置了一些假值)。在文本框中更改 ID 时,没有其他更新 - 除了 ID 本身 - setter 被很好地触发并且在调用 OnPropertyChanged 后读取新值。
我希望我遗漏了一些非常容易和愚蠢的东西。
-编辑:
当前状态:
TB_PacientID 工作(更新),TBL_NovyPacient 和 WP_PacientData 不工作(更新)。
我想:
所有视图都从视图模型(代码属性)更新。
-编辑 2
我从头开始创建了一个非常简单的问题示例:
A window - 两个文本框:
<Window x:Class="bindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TextBox x:Name="TestTextBox" Text="{Binding ID, Mode=TwoWay}"/>
<TextBox x:Name="SecondTextBox" Text="{Binding IsNew, Mode=TwoWay}"/>
</StackPanel>
</Window>
代码隐藏:
namespace bindingTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
}
}
和视图模型class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace bindingTest
{
public abstract class ViewModelBase
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class TestViewModel : ViewModelBase
{
private bool _attOne;
private int? id;
private bool _isNew;
public bool IsNew
{
get
{
return _isNew;
}
set
{
_isNew = value;
OnPropertyChanged();
}
}
public int? ID
{
get
{
return id;
}
set
{
this.id = value;
IsNew = true;
OnPropertyChanged();
}
}
}
}
我只是想要 - 如果我更改第一个文本框中的数字,我想在第二个文本框中自动显示 True。
我在您的代码示例中指出了三点:
- 您应该使用双向绑定来设置 ID。
- 您确定
_pacient = App.instance.sessionData.serviceProxy.pacientById(value.Value);
代码 returns 始终是相同的对象实例。
- 您是否正确使用了
INotifyPropertyChanged
界面?在大多数情况下,您引发了一个 属性 更改事件,如下所示:RaisePropertyChanged('PropertyName');
您正在调用:'OnPropertyChanged();'
希望这对您有所帮助...
是的,我很笨
我的 ViewModel 基础 class 在从另一个项目合并时丢失了 INotifyPropertyChanged 接口。
所以我调用了 OnPropertyChanged,但它一直是我自己的 OnPropertyChanged 而不是 WPF 绑定等待的接口的实现。
我的 WPF 应用程序以一种奇怪的方式工作 - 一些绑定有效,其他无效。
我有以下情况:
一个文本框 - 用户提供一个 ID。基于此 ID 加载或创建对象。其他一些属性由来自 loaded/new 对象的值更新。
ID 文本框的绑定工作正常。但是,其他两个视图(any other)不是。
我的代码示例: XAML:
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
<TextBlock Text="ID" FontFamily="Segoe UI Light" />
<TextBox x:Name="TB_PacientID" Width="100px" HorizontalAlignment="Left" Margin="5,0,0,0" Text="{Binding Path=PacientID}"/>
<TextBlock x:Name="TBL_NovyPacient" Text="nový pacient" Margin="5,0,0,0" Foreground="Green" FontWeight="Bold" Visibility="{Binding Path=IsNewPacient,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource BTVConverter}}"/>
</StackPanel>
<WrapPanel x:Name="WP_PacientData" Margin="-2,5,2,5" Visibility="{Binding PacientLoaded,Converter={StaticResource BTVConverter}}">
...
视图模型:
public int? PacientID
{
get
{
if (CurrentPacient == null)
return null;
return CurrentPacient.id;
}
set
{
if (value != null)
{
_pacient = App.instance.sessionData.serviceProxy.pacientById(value.Value);
if (_pacient == null)
{
CurrentPacient = new Pacient() { id = value.Value };
IsNewPacient = true;
}
else
{
CurrentPacient = _pacient;
}
OnPropertyChanged();
PacientLoaded = true;
}
}
}
// ...
public bool IsNewPacient
{
get{ return _isNewPacient; }
set
{
_isNewPacient = value;
OnPropertyChanged();
}
}
//...
public bool PacientLoaded
{
get{ return _pacientLoaded; }
set
{
_pacientLoaded = value;
OnPropertyChanged();
}
}
想法: 用户输入 ID,加载或创建对象并显示 WrapPanel。如果对象是新创建的,那么也会显示 TextBlock。 转换器工作正常(在另一个 window 中测试)。
当 window 加载时,绑定建立良好(如果我在 ctor 中设置了一些假值)。在文本框中更改 ID 时,没有其他更新 - 除了 ID 本身 - setter 被很好地触发并且在调用 OnPropertyChanged 后读取新值。
我希望我遗漏了一些非常容易和愚蠢的东西。
-编辑: 当前状态: TB_PacientID 工作(更新),TBL_NovyPacient 和 WP_PacientData 不工作(更新)。 我想: 所有视图都从视图模型(代码属性)更新。
-编辑 2 我从头开始创建了一个非常简单的问题示例: A window - 两个文本框:
<Window x:Class="bindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TextBox x:Name="TestTextBox" Text="{Binding ID, Mode=TwoWay}"/>
<TextBox x:Name="SecondTextBox" Text="{Binding IsNew, Mode=TwoWay}"/>
</StackPanel>
</Window>
代码隐藏:
namespace bindingTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
}
}
和视图模型class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace bindingTest
{
public abstract class ViewModelBase
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class TestViewModel : ViewModelBase
{
private bool _attOne;
private int? id;
private bool _isNew;
public bool IsNew
{
get
{
return _isNew;
}
set
{
_isNew = value;
OnPropertyChanged();
}
}
public int? ID
{
get
{
return id;
}
set
{
this.id = value;
IsNew = true;
OnPropertyChanged();
}
}
}
}
我只是想要 - 如果我更改第一个文本框中的数字,我想在第二个文本框中自动显示 True。
我在您的代码示例中指出了三点:
- 您应该使用双向绑定来设置 ID。
- 您确定
_pacient = App.instance.sessionData.serviceProxy.pacientById(value.Value);
代码 returns 始终是相同的对象实例。 - 您是否正确使用了
INotifyPropertyChanged
界面?在大多数情况下,您引发了一个 属性 更改事件,如下所示:RaisePropertyChanged('PropertyName');
您正在调用:'OnPropertyChanged();'
希望这对您有所帮助...
是的,我很笨
我的 ViewModel 基础 class 在从另一个项目合并时丢失了 INotifyPropertyChanged 接口。 所以我调用了 OnPropertyChanged,但它一直是我自己的 OnPropertyChanged 而不是 WPF 绑定等待的接口的实现。