WPF 绑定与代码隐藏中的手动更新
WPF Binding vs. Manual Update in Codebehind
所以,我有一个 UserControl,它显示从文件对象中提取的有关客户的基本信息。
控件如下所示:
<UserControl x:Class="Ns.Gui.pnlDebtor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="230" d:DesignWidth="460" xmlns:my="clr-namespace:Ns.Gui">
<Grid>
<GroupBox Header="Debtor" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="groupBox1" VerticalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="56" />
<RowDefinition Height="28" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*" />
<ColumnDefinition Width="380*" />
</Grid.ColumnDefinitions>
<Label Content="Name:" Height="28" HorizontalAlignment="Left" Name="lblName" VerticalAlignment="Top" />
<Label Content="Address:" Grid.Row="1" Height="28" HorizontalAlignment="Left" Name="lblAddress" VerticalAlignment="Top" />
<Label Content="Customer Nr.:" Grid.Row="2" Height="28" HorizontalAlignment="Left" Name="lblCustomerNr" VerticalAlignment="Top" />
<TextBox Grid.Column="1" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbName" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=DebtorName, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="1" Height="46" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbAddress" VerticalAlignment="Top" IsReadOnly="True" IsEnabled="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=Adresse, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbCustomerNr" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="True" />
<Button Content="Debtor Details" Grid.ColumnSpan="2" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="0,0,0,0" Name="btnDetails" VerticalAlignment="Top" />
</Grid>
</GroupBox>
</Grid>
</UserControl>
我的姓名和地址文本框绑定到 pnlDebtor UserControl 的 DebtorName 和 DebtorAddress 属性。
代码隐藏是这样的:
public partial class pnlDebtor : UserControl
{
private MyFile file = null;
public MyFile File
{
get
{
return file;
}
set
{
file = value;
tbCustomerNr.Text = file.CustomerNo;
}
}
private Contact debtor = null;
public Contact Debtor
{
get
{
if (debtor == null)
{
if (File != null)
{
debtor = AbstractDataObject.GetObject4ID<Contact>(File.DebtorID);
}
}
return debtor;
}
}
private Address debtorAddress = null;
public string Address
{
get
{
string result = string.Empty;
if (debtorAddress == null)
{
if (Debtor != null)
{
List<Address> lsAddresses = AbstractDataObject.GetObject4NonIdProperty<Address>("ContactID", Debtor.ID);
if (lsAddresses.Any())
{
debtorAddress = lsAddresses[0];
result += lsAddresses[0].Street + "\r\n"
+ lsAddresses[0].PostalCode + " " + lsAddresses[0].City;
}
}
}
else
{
result += debtorAddress.Street + "\r\n"
+ debtorAddress.PostalCode + " " + debtorAddress.City;
}
return result;
}
}
private string strDebtorName = string.Empty;
public string DebtorName
{
get
{
if (strDebtorName== string.Empty)
{
if (Debtor != null)
{
strDebtorName = Debtor.Name1;
if (Debtor.FirstName != null)
strSchuldnerName += ", " + Debtor.FirstName;
}
}
return strDebtorName;
}
}
public pnlDebtor()
{
InitializeComponent();
}
}
如您所见,与名称和地址文本框不同,我的 CustomerNr 文本框是在代码隐藏中填充的。当我传入我的文件对象时,我提取客户编号并将该值分配给相应文本框的文本 属性。这两种方法都有效,但第一种方法(绑定)似乎更适合 WPF。为什么?
对我来说,缺点是:
1)逻辑和表示没有分开。如果我将 xaml 发送给设计人员,他们可能会搞砸我的绑定。
2) 如果我正在调试并设置断点,我绑定的文本框的 Text 属性 总是一个空字符串。我看不到发生了什么。
那么,使用绑定有什么好处呢?为什么它是首选方法?使用小词。这是我的第一个 WPF 项目。 :)
我认为这里缺少的link是MVVM。您对代码隐藏中的属性的绑定意味着特定的 UserControl 仍然与特定的 class 紧密耦合。我不会说它比没有绑定的版本更好。代码隐藏 class 将无法编译,除非 XAML 页面与其捆绑在一起,因为存在对 tbCustomerNr.Text
的引用。
使用 MVVM 和绑定,ViewModel 完全 与 View 隔离。如果我愿意,我可以从我的程序中完全删除视图,并且 ViewModel 仍然可以编译而不会出现任何抱怨。这意味着可以轻松地重用 ViewModel 逻辑,并且可以将逻辑和 UI 开发任务完全分开。
所以,我有一个 UserControl,它显示从文件对象中提取的有关客户的基本信息。
控件如下所示:
<UserControl x:Class="Ns.Gui.pnlDebtor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="230" d:DesignWidth="460" xmlns:my="clr-namespace:Ns.Gui">
<Grid>
<GroupBox Header="Debtor" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="groupBox1" VerticalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="56" />
<RowDefinition Height="28" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*" />
<ColumnDefinition Width="380*" />
</Grid.ColumnDefinitions>
<Label Content="Name:" Height="28" HorizontalAlignment="Left" Name="lblName" VerticalAlignment="Top" />
<Label Content="Address:" Grid.Row="1" Height="28" HorizontalAlignment="Left" Name="lblAddress" VerticalAlignment="Top" />
<Label Content="Customer Nr.:" Grid.Row="2" Height="28" HorizontalAlignment="Left" Name="lblCustomerNr" VerticalAlignment="Top" />
<TextBox Grid.Column="1" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbName" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=DebtorName, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="1" Height="46" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbAddress" VerticalAlignment="Top" IsReadOnly="True" IsEnabled="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=Adresse, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbCustomerNr" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="True" />
<Button Content="Debtor Details" Grid.ColumnSpan="2" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="0,0,0,0" Name="btnDetails" VerticalAlignment="Top" />
</Grid>
</GroupBox>
</Grid>
</UserControl>
我的姓名和地址文本框绑定到 pnlDebtor UserControl 的 DebtorName 和 DebtorAddress 属性。
代码隐藏是这样的:
public partial class pnlDebtor : UserControl
{
private MyFile file = null;
public MyFile File
{
get
{
return file;
}
set
{
file = value;
tbCustomerNr.Text = file.CustomerNo;
}
}
private Contact debtor = null;
public Contact Debtor
{
get
{
if (debtor == null)
{
if (File != null)
{
debtor = AbstractDataObject.GetObject4ID<Contact>(File.DebtorID);
}
}
return debtor;
}
}
private Address debtorAddress = null;
public string Address
{
get
{
string result = string.Empty;
if (debtorAddress == null)
{
if (Debtor != null)
{
List<Address> lsAddresses = AbstractDataObject.GetObject4NonIdProperty<Address>("ContactID", Debtor.ID);
if (lsAddresses.Any())
{
debtorAddress = lsAddresses[0];
result += lsAddresses[0].Street + "\r\n"
+ lsAddresses[0].PostalCode + " " + lsAddresses[0].City;
}
}
}
else
{
result += debtorAddress.Street + "\r\n"
+ debtorAddress.PostalCode + " " + debtorAddress.City;
}
return result;
}
}
private string strDebtorName = string.Empty;
public string DebtorName
{
get
{
if (strDebtorName== string.Empty)
{
if (Debtor != null)
{
strDebtorName = Debtor.Name1;
if (Debtor.FirstName != null)
strSchuldnerName += ", " + Debtor.FirstName;
}
}
return strDebtorName;
}
}
public pnlDebtor()
{
InitializeComponent();
}
}
如您所见,与名称和地址文本框不同,我的 CustomerNr 文本框是在代码隐藏中填充的。当我传入我的文件对象时,我提取客户编号并将该值分配给相应文本框的文本 属性。这两种方法都有效,但第一种方法(绑定)似乎更适合 WPF。为什么?
对我来说,缺点是: 1)逻辑和表示没有分开。如果我将 xaml 发送给设计人员,他们可能会搞砸我的绑定。 2) 如果我正在调试并设置断点,我绑定的文本框的 Text 属性 总是一个空字符串。我看不到发生了什么。
那么,使用绑定有什么好处呢?为什么它是首选方法?使用小词。这是我的第一个 WPF 项目。 :)
我认为这里缺少的link是MVVM。您对代码隐藏中的属性的绑定意味着特定的 UserControl 仍然与特定的 class 紧密耦合。我不会说它比没有绑定的版本更好。代码隐藏 class 将无法编译,除非 XAML 页面与其捆绑在一起,因为存在对 tbCustomerNr.Text
的引用。
使用 MVVM 和绑定,ViewModel 完全 与 View 隔离。如果我愿意,我可以从我的程序中完全删除视图,并且 ViewModel 仍然可以编译而不会出现任何抱怨。这意味着可以轻松地重用 ViewModel 逻辑,并且可以将逻辑和 UI 开发任务完全分开。