C#调用WCF取数绑定ListView仅显示计数无正确值问题
问题成因
- 最核心的问题是WCF数据契约序列化标记缺失:你定义的
InterventiiCuEchipament类中,仅EchipamentInterventie属性添加了[DataMember]特性,其余需要传输的属性均未标记。WCF序列化时仅会识别带[DataMember]标记的属性,未标记属性的值不会被写入传输消息,客户端反序列化后这些属性均为类型默认值,无法绑定展示正确内容。 - 服务端查询存在延迟执行风险:你直接返回EF生成的
IQueryable查询对象,该类型的查询为延迟执行,WCF序列化枚举结果时如果数据上下文dataP已经释放,会触发查询异常,也可能导致返回结果结构不完整。 - 客户端调用和控件配置存在缺陷:直接用
.Result获取异步方法返回值容易造成UI线程死锁;如果ListView未配置对应列的字段绑定规则,就算数据正确传输到客户端,也无法识别要展示的字段,只会输出集合/对象的默认字符串表示。 - 服务契约存在冗余标记:
GetInterventiiCuEchipaments方法上方重复写了两次[OperationContract],虽然不一定直接引发错误,但属于不规范配置。
解决方法
- 补全数据契约标记,清理冗余配置
给所有需要跨WCF传输的属性添加[DataMember]特性,删除服务契约中重复的[OperationContract]标记,修正后代码如下:
public interface IServicePl { [OperationContract] IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments(); } [DataContract] public class InterventiiCuEchipament { [DataMember] public string EchipamentInterventie { get; set; } [DataMember] public int id_interventie { get; set; } [DataMember] public string tip_interventie { get; set; } [DataMember] public string responsabil { get; set; } [DataMember] public DateTime data_finalizare { get; set; } [DataMember] public bool status { get; set; } }
- 修正服务端查询逻辑,消除延迟执行问题
在服务端执行查询时用ToList()立即加载结果到内存集合,避免序列化时数据上下文已释放的问题,同时补全异常处理,修正后代码:
public IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments() { try { // 建议用using包裹EF上下文,确保资源正确释放 using (var dataP = new YourDbContext()) // 替换为你实际的EF上下文类名 { var query = from sel1 in dataP.interventiis join sel2 in dataP.sesizaris on sel1.id_interventie equals sel2.id_sesizare select new InterventiiCuEchipament() { id_interventie = sel1.id_interventie, EchipamentInterventie = sel2.echipament, tip_interventie = sel2.tip_sesizare, responsabil = sel1.responsabil, data_finalizare = (DateTime)sel1.data_finalizare, status = (bool)sel1.status }; // 立即执行SQL查询,转为内存集合再返回 return query.ToList(); } } catch (Exception ex) { throw new FaultException($"数据查询失败:{ex.Message}"); } }
- 配置ListView绑定规则,修正客户端调用逻辑
如果使用WPF的ListView控件,先在XAML中配置GridView列和对应字段的绑定关系:
<ListView x:Name="InterventiiList"> <ListView.View> <GridView> <GridViewColumn Header="干预ID" DisplayMemberBinding="{Binding id_interventie}"/> <GridViewColumn Header="关联设备" DisplayMemberBinding="{Binding EchipamentInterventie}"/> <GridViewColumn Header="干预类型" DisplayMemberBinding="{Binding tip_interventie}"/> <GridViewColumn Header="负责人" DisplayMemberBinding="{Binding responsabil}"/> <GridViewColumn Header="完成时间" DisplayMemberBinding="{Binding data_finalizare}"/> <GridViewColumn Header="完成状态" DisplayMemberBinding="{Binding status}"/> </GridView> </ListView.View> </ListView>
客户端调用WCF服务时改用await异步方式,避免.Result造成的UI线程死锁,不需要手动调用Items.Refresh(),赋值ItemsSource后控件会自动刷新:
if (client.InnerChannel.State != CommunicationState.Faulted) { var ListaInterventii = (await client.GetInterventiiCuEchipamentsAsync()).ToList(); InterventiiList.ItemsSource = ListaInterventii; }
如果使用WinForm平台的ListView控件,需要先将控件的View属性设置为Details,添加对应列头后,通过循环遍历结果集创建ListViewItem添加到控件中即可。
- 更新客户端服务引用
服务端代码修改完成后,在客户端项目中找到对应的WCF服务引用,右键选择“更新服务引用”,重新生成客户端代理类,确保客户端的数据契约定义和服务端一致。
内容的提问来源于stack exchange,提问作者BMA
相关产品推荐
相关产品推荐

