为什么双向绑定不能按预期工作?
Why twoway binding doen't work as expected?
我需要一些绑定方面的帮助。双路模式根本不起作用。
我用传递给构造函数的数据填充我的 window,它工作正常。
问题是即使我使用 Twoway 绑定,我也无法重写 window 控件中输入的某些数据。
下面是我如何打开 window
var tempInregistrare = BaseConnection.GetInregistrareById(itemSelected.InregistrareId.ToString());
var tichet = new TichetView(new InregistrareModel {
Id =tempInregistrare.Id,
NumeFurnizor = tempInregistrare.NumeFurnizor,
IdFurnizor = tempInregistrare.IdFurnizor,
NumeProdus = tempInregistrare.NumeProdus......
ticket.Show();
这是 window 构造函数,DataContext 设置为 self。
public TichetView(InregistrareModel inregistrare)
{
InitializeComponent();
InregistrareModel = inregistrare;
DataContext = this;
grdButtonsPrint.Visibility = Visibility.Visible;
}
public InregistrareModel InregistrareModel
{
get => inregistrareModel;
set
{
if (value != inregistrareModel)
{
inregistrareModel = value;
NotifyPropertyChanged();
}
}
}
public class InregistrareModel
{
public int Id { get; set; }
public int IdProdus { get; set; }
public int IdFurnizor { get; set; }
public string NumeProdus { get; set; }
public string NumeFurnizor { get; set; }
public string NrAuto { get; set; }
public string NumeSofer { get; set; }
public double CantitateInitiala { get; set; }
public double CantitateIesire { get; set; }
public double Umiditate { get; set; }
public double CantitateScazuta { get; set; }
public double CantitateMarfa { get; set; }
public DateTime DataIntrare { get; set; }
public DateTime DataIesire { get; set; }
public FurnizorModel Furnizor { get; set; }
public int NIR { get; set; }
}
这里是 Xaml,共 window
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">Intrare</TextBlock>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding InregistrareModel.CantitateInitiala}"/>
<TextBlock Grid.Row="4" Grid.Column="2" VerticalAlignment="Center">Umiditatea (%)</TextBlock>
<TextBox x:Name="txtUmiditate" Grid.Row="4" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.Umiditate, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="2" VerticalAlignment="Center">Cantitatea scazuta</TextBlock>
<TextBox x:Name="txtCantitateScazuta" Grid.Row="5" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.CantitateScazuta, Mode=TwoWay}"/>
<TextBlock Grid.Row="6" Grid.Column="2" VerticalAlignment="Center">Iesire</TextBlock>
<TextBox Grid.Row="6" Grid.Column="3" Text="{Binding InregistrareModel.CantitateIesire}"/>
<TextBlock Grid.Row="7" Grid.Column="2" VerticalAlignment="Center">Dată iesire</TextBlock>
<TextBox Grid.Row="7" Grid.Column="3" Text="{Binding InregistrareModel.DataIesire,StringFormat='{}{0:HH:HH dd/M/yyyy}'}"/>
<TextBlock Grid.Row="10" Grid.Column="2" VerticalAlignment="Center">Net</TextBlock>
<TextBox Grid.Row="10" Grid.Column="3" Text="{Binding InregistrareModel.CantitateMarfa}"/>
除了我手动填写的第二个和第三个文本框外,所有文本框都填充了数据。
我现在无法实现的目标是从第一个文本框(InregistrareModel.CantitateInitiala)中获取数据以输入第三个(txtCantitateScazuta)一些数据并在最后一个文本框中显示结果,所以在我用这些数据更新我的数据库之后.
- 您应该使 ViewModel 成为一个单独的 file/class。我们称它为
TichetViewModel
。这个 class 应该有 InregistrareModel
。像这样:
public class TichetViewModel : ObservableObject
{
private InregistrareModel _InregistrareModel;
public InregistrareModel InregistrareModel
{
get { return _InregistrareModel; }
set
{
if (value != _InregistrareModel)
{
_InregistrareModel = value;
NotifyPropertyChanged();
}
}
}
public TichetViewModel()
{
InregistrareModel = new InregistrareModel();
}
}
- 然后在后面的代码或 xaml 中设置
TichetView
的 DataContext
。
后面的代码:
TichetView.xaml.cs
public TichetView()
{
InitializeComponent();
DataContext = new TichetViewModel();
}
或 xaml
TichetView.xaml
<Window.DataContext>
<local:TichetViewModel />
</Window.DataContext>
我喜欢在 xaml 中这样做,因为 Visual Studio 中的 Intellisense 会选择它并根据 classes 自动完成。
- 对
InregistrareModel
的属性实施 INotifyPropertyChanged
。像这样:
public class InregistrareModel : ObservableObject
{
private int _Id;
public int Id
{
get { return _Id; }
set
{
if (value != _Id)
{
_Id = value;
NotifyPropertyChanged();
}
}
}
private string _NumeProdus;
public string NumeProdus
{
get { return _NumeProdus; }
set
{
if (value != _NumeProdus)
{
_NumeProdus = value;
NotifyPropertyChanged();
}
}
}
}
我完全同意@Peter Boone。
您在解决方案中有很多严重的架构错误,并且有充分的理由需要完全重做。
但是,如果您没有这样的机会,请尝试实施此选项。
对于更改的字段(TextBox、TextBlock),在 Window 中声明属性。
在这些属性的主体中,实现与父容器 (InregistrereModel) 和其他属性的通信。
假设您有一个影响 CantitateScazuta 属性.
值的 CantitateInitiala 属性
public InregistrareModel InregistrareModel
{
get => inregistrareModel;
set
{
if (value != inregistrareModel)
{
inregistrareModel = value;
NotifyPropertyChanged();
CantitateInitiala = InregistrareModel.CantitateInitiala;
}
}
public double CantitateInitiala
{
get => InregistrareModel.CantitateInitiala;
set
{
if (value != InregistrareModel.CantitateInitiala)
{
InregistrareModel.CantitateInitiala = value;
NotifyPropertyChanged();
// Calculation of the CantitateScazuta value
double cantSc = CantitateInitiala / 123.45;
CantitateScazuta = cantSc;
}
}
}
public double CantitateScazuta
{
get => InregistrareModel.CantitateScazuta;
set
{
if (value != InregistrareModel.CantitateScazuta)
{
InregistrareModel.CantitateScazuta = value;
NotifyPropertyChanged();
}
}
}
在 XAML 中,更改这些字段的绑定:
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">Intrare</TextBlock>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding CantitateInitiala}"/>
<TextBlock Grid.Row="4" Grid.Column="2" VerticalAlignment="Center">Umiditatea (%)</TextBlock>
<TextBox x:Name="txtUmiditate" Grid.Row="4" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.Umiditate, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="2" VerticalAlignment="Center">Cantitatea scazuta</TextBlock>
<TextBox x:Name="txtCantitateScazuta" Grid.Row="5" Grid.Column="3" IsReadOnly="False" Text="{Binding CantitateScazuta, Mode=TwoWay}"/>
但是你需要仔细考虑属性依赖的算法,如果它们有循环依赖的话。
也就是说,不仅改变CantitateInitiala会影响CantitateScazuta的值,而且CantitateInitiala与改变CantitateScazuta之间也存在反比关系。
我需要一些绑定方面的帮助。双路模式根本不起作用。 我用传递给构造函数的数据填充我的 window,它工作正常。 问题是即使我使用 Twoway 绑定,我也无法重写 window 控件中输入的某些数据。 下面是我如何打开 window
var tempInregistrare = BaseConnection.GetInregistrareById(itemSelected.InregistrareId.ToString());
var tichet = new TichetView(new InregistrareModel {
Id =tempInregistrare.Id,
NumeFurnizor = tempInregistrare.NumeFurnizor,
IdFurnizor = tempInregistrare.IdFurnizor,
NumeProdus = tempInregistrare.NumeProdus......
ticket.Show();
这是 window 构造函数,DataContext 设置为 self。
public TichetView(InregistrareModel inregistrare)
{
InitializeComponent();
InregistrareModel = inregistrare;
DataContext = this;
grdButtonsPrint.Visibility = Visibility.Visible;
}
public InregistrareModel InregistrareModel
{
get => inregistrareModel;
set
{
if (value != inregistrareModel)
{
inregistrareModel = value;
NotifyPropertyChanged();
}
}
}
public class InregistrareModel
{
public int Id { get; set; }
public int IdProdus { get; set; }
public int IdFurnizor { get; set; }
public string NumeProdus { get; set; }
public string NumeFurnizor { get; set; }
public string NrAuto { get; set; }
public string NumeSofer { get; set; }
public double CantitateInitiala { get; set; }
public double CantitateIesire { get; set; }
public double Umiditate { get; set; }
public double CantitateScazuta { get; set; }
public double CantitateMarfa { get; set; }
public DateTime DataIntrare { get; set; }
public DateTime DataIesire { get; set; }
public FurnizorModel Furnizor { get; set; }
public int NIR { get; set; }
}
这里是 Xaml,共 window
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">Intrare</TextBlock>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding InregistrareModel.CantitateInitiala}"/>
<TextBlock Grid.Row="4" Grid.Column="2" VerticalAlignment="Center">Umiditatea (%)</TextBlock>
<TextBox x:Name="txtUmiditate" Grid.Row="4" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.Umiditate, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="2" VerticalAlignment="Center">Cantitatea scazuta</TextBlock>
<TextBox x:Name="txtCantitateScazuta" Grid.Row="5" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.CantitateScazuta, Mode=TwoWay}"/>
<TextBlock Grid.Row="6" Grid.Column="2" VerticalAlignment="Center">Iesire</TextBlock>
<TextBox Grid.Row="6" Grid.Column="3" Text="{Binding InregistrareModel.CantitateIesire}"/>
<TextBlock Grid.Row="7" Grid.Column="2" VerticalAlignment="Center">Dată iesire</TextBlock>
<TextBox Grid.Row="7" Grid.Column="3" Text="{Binding InregistrareModel.DataIesire,StringFormat='{}{0:HH:HH dd/M/yyyy}'}"/>
<TextBlock Grid.Row="10" Grid.Column="2" VerticalAlignment="Center">Net</TextBlock>
<TextBox Grid.Row="10" Grid.Column="3" Text="{Binding InregistrareModel.CantitateMarfa}"/>
除了我手动填写的第二个和第三个文本框外,所有文本框都填充了数据。 我现在无法实现的目标是从第一个文本框(InregistrareModel.CantitateInitiala)中获取数据以输入第三个(txtCantitateScazuta)一些数据并在最后一个文本框中显示结果,所以在我用这些数据更新我的数据库之后.
- 您应该使 ViewModel 成为一个单独的 file/class。我们称它为
TichetViewModel
。这个 class 应该有InregistrareModel
。像这样:
public class TichetViewModel : ObservableObject
{
private InregistrareModel _InregistrareModel;
public InregistrareModel InregistrareModel
{
get { return _InregistrareModel; }
set
{
if (value != _InregistrareModel)
{
_InregistrareModel = value;
NotifyPropertyChanged();
}
}
}
public TichetViewModel()
{
InregistrareModel = new InregistrareModel();
}
}
- 然后在后面的代码或 xaml 中设置
TichetView
的DataContext
。
后面的代码:
TichetView.xaml.cs
public TichetView()
{
InitializeComponent();
DataContext = new TichetViewModel();
}
或 xaml
TichetView.xaml
<Window.DataContext>
<local:TichetViewModel />
</Window.DataContext>
我喜欢在 xaml 中这样做,因为 Visual Studio 中的 Intellisense 会选择它并根据 classes 自动完成。
- 对
InregistrareModel
的属性实施INotifyPropertyChanged
。像这样:
public class InregistrareModel : ObservableObject
{
private int _Id;
public int Id
{
get { return _Id; }
set
{
if (value != _Id)
{
_Id = value;
NotifyPropertyChanged();
}
}
}
private string _NumeProdus;
public string NumeProdus
{
get { return _NumeProdus; }
set
{
if (value != _NumeProdus)
{
_NumeProdus = value;
NotifyPropertyChanged();
}
}
}
}
我完全同意@Peter Boone。 您在解决方案中有很多严重的架构错误,并且有充分的理由需要完全重做。 但是,如果您没有这样的机会,请尝试实施此选项。
对于更改的字段(TextBox、TextBlock),在 Window 中声明属性。 在这些属性的主体中,实现与父容器 (InregistrereModel) 和其他属性的通信。
假设您有一个影响 CantitateScazuta 属性.
值的 CantitateInitiala 属性 public InregistrareModel InregistrareModel
{
get => inregistrareModel;
set
{
if (value != inregistrareModel)
{
inregistrareModel = value;
NotifyPropertyChanged();
CantitateInitiala = InregistrareModel.CantitateInitiala;
}
}
public double CantitateInitiala
{
get => InregistrareModel.CantitateInitiala;
set
{
if (value != InregistrareModel.CantitateInitiala)
{
InregistrareModel.CantitateInitiala = value;
NotifyPropertyChanged();
// Calculation of the CantitateScazuta value
double cantSc = CantitateInitiala / 123.45;
CantitateScazuta = cantSc;
}
}
}
public double CantitateScazuta
{
get => InregistrareModel.CantitateScazuta;
set
{
if (value != InregistrareModel.CantitateScazuta)
{
InregistrareModel.CantitateScazuta = value;
NotifyPropertyChanged();
}
}
}
在 XAML 中,更改这些字段的绑定:
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">Intrare</TextBlock>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding CantitateInitiala}"/>
<TextBlock Grid.Row="4" Grid.Column="2" VerticalAlignment="Center">Umiditatea (%)</TextBlock>
<TextBox x:Name="txtUmiditate" Grid.Row="4" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.Umiditate, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="2" VerticalAlignment="Center">Cantitatea scazuta</TextBlock>
<TextBox x:Name="txtCantitateScazuta" Grid.Row="5" Grid.Column="3" IsReadOnly="False" Text="{Binding CantitateScazuta, Mode=TwoWay}"/>
但是你需要仔细考虑属性依赖的算法,如果它们有循环依赖的话。 也就是说,不仅改变CantitateInitiala会影响CantitateScazuta的值,而且CantitateInitiala与改变CantitateScazuta之间也存在反比关系。