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 开发任务完全分开。