【问题标题】:Binding of Checkbox IsChecked to EntityFramework not working in MVVM pattern将 Checkbox IsChecked 绑定到 EntityFramework 在 MVVM 模式中不起作用
【发布时间】:2014-07-18 02:09:45
【问题描述】:

总结:如何从 UI 更新数据模型中的 Isdone 属性? (我在 Google 上阅读的内容没有任何帮助。我希望有一个简单的答案。)

我试图尽可能完整,只显示相关代码。

初始化时,ListView 的复选框正确显示为被数据库 Actiontaken 的值选中。

但是,当从 UI 中选中 Checkbox 时,不会命中 Isdone 属性的设置代码。

在 Visual Studio 2010 中,我将解决方案分为以下项目: 1.混沌数据, 2. Chaos.DataService, 3. 测试客户端。

Chaos.Data 使用带有部分类的 EntityFramework 从数据库提供数据。在此,我为单独的业务规则添加了一个单独的文件:

namespace Chaos.Data
{
 partial class Lab
   {
    private Boolean? isdone;
    public virtual Boolean? Isdone
    {
        get
        {
            isdone = (Actiontaken == 1 || Actiontaken == 129) ? true : false;
            return isdone;
        }
        set
        {
            if (this.isdone != value)
            {
                this.isdone = value;
                this.Actiontaken = 1;
                this.OnPropertyChanged("Isdone");
                if (this.isdone == true) this.setallcheckbox("Isdone");
            }
        }
    }

Chaos.DataService 是一个 WCF 服务。在此,我定义了:

namespace Chaos.DataService
{
  [OperationContract]
    public IEnumerable<Lab> GetAllLabs(String groupid, DateTime? encountertime)
    {
        if (encountertime == null) return null;

        using (var context = new ChaosModel())
        {
            var query = from lab in context.Labs
                        where lab.Groupid == groupid && lab.Tposted.Date <= ((DateTime)encountertime).Date
                        select lab;

            var result = context.CreateDetachedCopy(query.ToList());
            return result;
        }
    }

}

TestClient 使用对 Chaos.DataService 的引用(...是的,为了安全起见,我已经更新了 TestClient 中的服务引用。)TestClient 的观点如下:

XAML

<ListView ItemContainerStyle="{StaticResource ItemContStyle}" 
              ItemsSource="{Binding Labs}"  
              HorizontalAlignment="Stretch"
              Margin="12,99,0,103" Name="listViewLabs" VerticalAlignment="Stretch"  >

        <ListView.View>
            <GridView>

                <GridViewColumn Header="Done" Width="40">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding Isdone, Mode=TwoWay}" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
    .................

C# 代码隐藏:

 namespace Chaos.UI.View
 {
    public partial class PatientLabsWindow : Window
    {
        public PatientLabsWindow(EncounterDetail encounter)
        { 
          InitializeComponent();

        ViewModelPatientLabs vm = new ViewModelPatientLabs(encounter);
        this.DataContext = vm;
        vm.CloseAction = new Action(() => this.Close());
    }
  }
}

在 ViewModel 中,我定义了:

 namespace Chaos.UI.ViewModel
 {
  class ViewModelPatientLabs : ViewModelBase
 {
        private ChaosServiceClient serviceClient = new ChaosServiceClient();

        // Constructor
        public ViewModelPatientLabs(EncounterDetail encounter)
        {
            this.Encounter = encounter;
        }

    private EncounterDetail encounter;
    public EncounterDetail Encounter 
    {
        get
        {
            return this.encounter;
        }
        set
        {
                this.encounter = value;
                this.OnPropertyChanged("Encounter");
                this.GetAllLabs();
        }
    }

    private void GetAllLabs()
    {
        // consume the WCF service.
        this.serviceClient.GetAllLabsCompleted += (s, e) =>
        {
            this.Labs = e.Result;
        };

        // call the WCF service -- Async
        this.serviceClient.GetAllLabsAsync(Encounter.groupid, Encounter.tencounter);
    }

    private IEnumerable<Lab> labs;
    public IEnumerable<Lab> Labs
    {
        get
        {
            return this.labs;
        }
        set
        {
            this.labs = value;
            this.OnPropertyChanged("Labs");
        }
    }

}
}

如果我遗漏了什么,请告诉我。

再次重申,ListView 的复选框已从数据库模型正确更新。但是从 UI 中检查该框并不会在添加的 Labs 业务类中为 Isdone 设置代码。

我该如何解决这个问题?有什么想法吗?

编辑:Lab 是 Chaos.Data 命名空间中定义的类。它是由 Telerik DataAccess 生成的

  namespace Chaos.Data  
   {
  public partial class Lab : INotifyPropertyChanged
   {
        ......
       }
     }  

为了不触及这个自动生成的文件,我将自己添加的内容与单独的文件添加到部分类中,如上所示。

编辑:我对这一切都很陌生。我发现有趣的是,当在客户端项目中更新服务时,WCF 将我的部分类添加到 Lab 实体中:

  namespace Chaos.UI.ChaosService {
   using System.Runtime.Serialization;
   using System;
 ..............................

[System.Runtime.Serialization.OptionalFieldAttribute()]
    private System.Nullable<bool> IsdoneField;
[System.SerializableAttribute()]
public partial class Lab : object, System.Runtime.Serialization.IExtensibleDataObject,      
System.ComponentModel.INotifyPropertyChanged {....

...............

 [System.Runtime.Serialization.OptionalFieldAttribute()]
    private System.Nullable<bool> IsdoneField;

并且从 WCF 查询返回的 Labs 属于 IEnumerable 类型,而不是可观察的集合。那么 View 绑定正在更新 WCF 中的字段并且永远不会被传输回模型的问题吗???

请帮助某人??

【问题讨论】:

  • ObservableCollection 集合在哪里?
  • Labs 在 EntitiesModel.cs 的 Chaos.Data 项目中定义。该文件由 Telerik DataAccess Update Model 从数据库自动构建,定义为: public IQueryable Labs { get { return this.GetAll(); } }
  • 你希望 Isdone 的 setter 属性在被点击时触发?

标签: wpf entity-framework wcf mvvm checkbox


【解决方案1】:

如果您想让 IsDone 的 setter 属性在被点击时触发,您需要让 Lab 实现 INotifyPropertyChanged 并在 IsDone 的 setter 属性上引发 PropertyChanged 事件。

这是一个工作示例。

查看

<Window x:Class="WpfUserControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <ListView ItemsSource="{Binding Labs}" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Done" Width="40">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding IsDone, Mode=TwoWay}" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

代码隐藏

public partial class MainWindow : Window
{
    public MainWindow()
    {    
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}    
public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        Labs = new[] { new Lab { IsDone = true } };
    }    
    public IEnumerable<Lab> Labs { get; set; }
}    
public class Lab : INotifyPropertyChanged
{
    private bool? _isDone;
    public bool? IsDone
    {
        get { return _isDone; }
        set
        {
            _isDone = value;
            OnPropertyChanged("IsDone");
        }
    }    
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

【讨论】:

  • @yulaim Lab 被定义为公共部分类 Lab : INotifyPropertyChanged { 请看我上面的编辑...它仍然不起作用????
  • @yulaim 请注意,Isdone 不是原始实体的一部分,而是使用部分类 Lab 添加到单独的文件中。这有关系吗?
  • 不,没关系,我只是试了一下,它仍然可以使用部分。
  • @AlanWayne,如何删除此代码if (this.isdone != value)
  • 嗯...在代码隐藏中它可以工作。我在客户端项目和数据模型之间使用 WCF 服务在 MVVM 模式中进行了设置。我一定是在接线中遗漏了什么,但不知道在哪里???感谢您的帮助!
【解决方案2】:

我对这一切都不熟悉,但我发现这对我来说很有效。

在我的特定情况下,我需要在 UI 的同一行上对多个复选框进行分组。所以,最终,我需要知道点击了哪个复选框以及在哪一行。总之,这将需要对 UI 绑定进行参数调用。完全坚持 MVVM 模型需要添加类似 RelayCommand 或其他辅助类的东西。由于我已经在使用 WCF 服务与数据层(模型)进行通信,因此我决定概括“视图”并允许一些代码隐藏。 (任何人,如果太错误,请更正)。

正如最初的问题所述,数据模型中 Isdone 属性的 set{} 方法从未被命中。我怀疑这是因为没有使用 WCF 服务将属性转发到后端。此外,UI 绑定到 Isdone,但没有对 Isdone 实体的引用。

长话短说,这些变化使它起作用了: 在 UI 中,添加到 ListView

SelectedItem="{Binding CurrentLab}"

在 UI 中,将 Click 添加到复选框:

<CheckBox IsChecked="{Binding Isdone, Mode=TwoWay}" Name="chkIsDone" Click="chkIsDone_Click" />

在代码隐藏中,添加:

  void chkIsDone_Click(object sender, RoutedEventArgs e)
    {
        var cb = sender as CheckBox;
        Lab lab = (Lab)cb.DataContext;
        if (lab.Isdone == true) this.setallcheckbox(lab, "Isdone");
        listViewLabs.SelectedItem = lab;
    }

在 ViewModel 中,添加:

  private Lab currentLab;
    public Lab CurrentLab
    {
        get
        {
            return this.currentLab;
        }

        set
        {
            this.currentLab = value;
            this.OnPropertyChanged("CurrentLab");
        }
    }

现在 View 可以正确显示,并且 Isdone 属性已正确设置在它被单击的特定行上。

如果有人有更好的方法,我会更感兴趣。

【讨论】:

    猜你喜欢
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多