wcf - 带有对象列表的数据绑定(bind) Silverlight 组合框 - 工作但丑陋

标签 wcf silverlight data-binding combobox

我正在开发一个业务应用程序,使用 Silverlight 作为 UI,使用 WCF Web 服务作为后端。在数据库中我有许多查找表。当 WCF 服务返回业务对象时,其中一个属性包含查找表中的整行,而不仅仅是外键,因此在 UI 中我可以显示查找表中的描述等内容,而无需再次调用服务。我目前想做的是提供一个绑定(bind)到整个查找值列表的组合框并使其正确更新。我在本例中处理的业务对象称为 Session,查找称为 SessionType。

下面是组合框的定义。 DataContext 设置为 Session 的实例。我正在设置 ItemTemplate,因为组合框显示的不仅仅是字符串列表。

<ComboBox 
x:Name="SessionTypesComboBox"
ItemTemplate="{StaticResource SessionTypeDataTemplate}"
ItemsSource="{Binding Source={StaticResource AllSessionTypes}}"
SelectedItem="{Binding Path=SessionType, Mode=TwoWay}"
/>

业务对象和查找表都通过 Web 服务异步加载。如果我什么都不做,组合框列表将填充 SessionTypes,但不会显示 Session 中的初始 SessionType 值。但是,如果组合框选择发生更改, session 将使用正确的 session 类型进行更新。

似乎发生的情况是 SelectedItem 绑定(bind)无法将 Session 中的 SessionType 与其在 SessionType 列表中的等效项相匹配。对象值相同,但引用不同。

我发现的解决方法是加载 Session 和 SessionTypes 列表,然后使用 SessionTypes 列表中相应的 SessionType 更新 Session 的当前 SessionType。如果我这样做,组合框就会正确显示。然而对我来说,这有一种不好的代码味道。因为所有内容都是异步加载的,所以我必须确定所有内容何时可用。我是这样做的:

在我的 Silverlight 用户控件的代码隐藏中:

// incremented every time we get data back during initial form load.
private volatile int m_LoadSequence = 0;

...

// Loaded event, called when the form is er... loaded.
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    // load session types
    var sessionTypes = this.Resources["AllSessionTypes"] as Lookups.AllSessionTypes;
    if (sessionTypes != null)
    {
        sessionTypes.DataLoadCompleted += (s, ea) =>
        {
            IncrementLoadSequence();
        };
        sessionTypes.LoadAsync();
    }

    // start loading another lookup table, same as above
    // omitted for clarity

    // set our DataContect to our business object (passed in when form was created)
    this.LayoutRoot.DataContext = this.m_Session;
    IncrementLoadSequence();
}

// This is the smelly part. This gets called by OnBlahCompleted events as web service calls return.
private void IncrementLoadSequence()
{
    // check to see if we're expecting any more service calls to complete.
    if (++m_LoadSequence < 3)
        return;

    // set lookup values on m_Session to the correct one in SessionType list.

    // Get SessionType list from page resources
    var sessionTypes = this.Resources["AllSessionTypes"] as Lookups.AllSessionTypes;

    // Find the matching SessionType based on ID
    this.m_Session.SessionType = sessionTypes.Where((st) => { return st.SessionTypeID == this.m_Session.SessionType.SessionTypeID; }).First();

    // (other lookup table omitted for clarity)
}

所以基本上我有一个计数器,每次从网络服务获取数据时它都会递增。因为我期待 3 个东西(核心业务对象 + 2 个查找表),所以当计数器达到 3 时,我会匹配引用。

对我来说,这看起来很老套。我宁愿看到组合框指定 ValueMemberPath 和 SelectedValue 以将所选项目与列表中的项目相匹配。

任何人都可以看到更干净的方法吗?这种情况在商业应用程序中很常见,所以我确信一定有一种很好的方法来做到这一点。

最佳答案

杰夫,

为了确认我理解您的问题:数据绑定(bind)基础设施似乎无法识别认为“相等”的两个对象实际上是相等的 - 因此最初的SelectedItem 设置不正确,因为数据绑定(bind)在 StaticResource 集合中找不到与 Session.SessionType 匹配的引用等于对象。 您可以通过“扁平化”引用来解决这个问题(即,您强制 Session.SessionTypeWhere((st).. .First()代码。

我们有一个 similar problem .

Silverlight 不会仅仅因为知道它们代表相同的数据而自动将来自不同“源”的两个对象“等同”,这确实是有道理的。就像您所说的“对象值相同但引用不同”。但是如何使数据绑定(bind)将它们等同起来呢?

我们想到/尝试过的事情:

  • 在类上实现 .Equals()(在您的情况下为 SessionType)

  • 在类上实现运算符 ==(在您的情况下为 SessionType)

  • 实现IEquatable在类上(SessionType 在您的情况下)

  • 使集合仅包含 String 并绑定(bind)到字符串属性

但最终我们放弃了并使用与您相同的方法 - 从“集合”中“提取”正确的引用等于对象(在加载所有内容之后)并将其插入 SelectedItem绑定(bind)属性。

我同意你关于代码气味的看法,并且怀疑一定有更好的解决方案。到目前为止,我们在属性访问器和无操作 IValueConverter 中的所有调试都没有找到解决方案 - 但如果我们找到了,我也会将其发布回此处。

关于wcf - 带有对象列表的数据绑定(bind) Silverlight 组合框 - 工作但丑陋,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/475537/

相关文章:

c# - 内容被阻止,因为它没有由有效的安全证书签名。

c# - 我的 WPF 自定义控件 Datacontext 正在取代父控件

javascript - Angular : use a variable into <div>

c# - 仅在 WCF Web 服务中需要某些方法的凭据

c# - WCF 服务能否同时支持缓冲和流式传输模式?

c# - 如何在 Silverlight 中向控件添加状态?

c# - 无法加载程序集 'Microsoft.AI.Web'

asp.net - WCF-元数据交换配置

时间:2019-03-17 标签:c#WindowsShutdownprocesshirides

c# - ObservableCollection 优于 ObjectSet