【问题标题】:How can I get my Partial Class to update如何让我的部分课程更新
【发布时间】:2012-01-27 20:18:47
【问题描述】:

我有一个使用实体框架模型的 WPF 应用程序。其中一个实体是员工类型。此实体具有 LastName 和 FirstName 属性等。但是在我的 xaml 中,我想在我的 DataGrid 中显示一个全名。所以我创建了这个 Partial Class 来返回全名,并在 DataGrid 中显示这个属性。这很好用。 FullName 按预期显示在 DataGrid 中。

public partial class Employee
{
    public string FullName
    {
        get { return LastName.Trim() + ", " + FirstName.Trim(); }
    }
}

我遇到的问题是我的编辑表单有文本框绑定到 LastName 和 FirstName 属性。当我更新 CompanyName、LastName、FirstName、HireDate 等值时,DataGrid 中所有已更改的列都会正确更新,但 FullName 属性不会更新。

为什么我的 FullName 部分类没有得到更新,而 DataGrid 的其余属性却得到了更新?我该如何纠正这个问题?

这是我的编辑表单 xaml。

<TextBox Grid.Column="1" Name="txtCompany" Text="{Binding SelectedEmployee.Company, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Column="1" Name="txtFirstName" Text="{Binding SelectedEmployee.FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Column="1" Name="txtLastName" Text="{Binding SelectedEmployee.LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Column="1" Name="txtFullName" Grid.Row="2"  Margin="2" Text="{Binding SelectedEmployee.FullName" />    -- Also show as column in DataGrid

【问题讨论】:

  • 你在使用属性改变事件吗?

标签: wpf entity-framework partial-classes


【解决方案1】:

WPF 中的更改通知是通过INotifyPropertyChanged 接口完成的。

它与实体框架开箱即用,因为生成的实体(通过默认的 edmx 模板)实现了这个接口,并且生成的属性设置器会触发 PropertyChanged 事件。

您的新属性不会引发此事件,而是因为它是根据 LastNameFirstName 计算得出的,因此当这两个发生更改时,您需要引发 PropertyChanged 事件。

幸运的是,EF 会在每个属性设置器中生成一个名为 OnSomePropertyChanged 的部分方法,您可以从中引发事件:

public partial class Employee
{
    public string FullName
    {
        get { return LastName.Trim() + ", " + FirstName.Trim(); }
    }

    partial void OnLastNameChanged()
    {
         base.OnPropertyChanged("FullName");
    }

    partial void OnFirstNameChanged()
    {
         base.OnPropertyChanged("FullName");
    }
}

【讨论】:

    【解决方案2】:

    使用带有适当 StringFormat 的 MultiBinding 将避免任何额外的代码,并且将是一个更通用的解决方案,因为它不依赖于 EF 所做的事情。请注意带有前导 {} 的格式字符串的有趣表示法,它在 XAML 中的字符串中启用花括号:

    <TextBlock Name="fullNameTextBlock">
        <TextBlock.Text>
            <MultiBinding StringFormat="{}{1}, {0}">
                <Binding Path="FirstName"/>
                <Binding Path="LastName"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>
    

    更复杂但更通用的方法是将 MultiBinding 与 IMultiValueConverter 结合使用。你会像这样创建一个 MultiBinding:

    <TextBlock Name="fullNameTextBlock">
        <TextBlock.Text>
            <MultiBinding Converter="{StaticResource FullNameConverter}">
                <Binding Path="FirstName"/>
                <Binding Path="LastName"/>
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>
    

    转换器基本上如下所示:

    public class FullNameConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ((string)values[1]).Trim() + ", " + ((string)values[0]).Trim();
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    【讨论】:

    • 你甚至不需要转换器,你可以使用绑定的stringformat选项
    • 感谢 Bob 指出这一点。我没有意识到这一点,它使解决方案变得更加容易,因为它完全避免了任何代码。我已经相应地编辑了我的答案。
    • 这会很好,但在我的情况下,FullName 属性将在 UI 中的许多地方使用。
    猜你喜欢
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 2022-01-25
    • 2019-04-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    相关资源
    最近更新 更多