如何在MVVM模式中访问viewmodel中的文本框值?我的代码如下 [英] How to access textbox value in viewmodel in MVVM pattern? My code are as follows

查看:67
本文介绍了如何在MVVM模式中访问viewmodel中的文本框值?我的代码如下的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是MVVM的初学者,我的问题是我无法访问ViewModel中的MainWindow(View)文本框值。



我尝试了什么:



这是模型属性

I am beginner in MVVM, my problem is i am not able to access MainWindow(View) textBox value in ViewModel.

What I have tried:

This is Model properties

<pre> public class ModelEntity:INotifyPropertyChanged
    {
        public ModelEntity()
        { }
        private string _firstname;
        private string _lastName;
        private string _address;
        private string _contact;
        private string _dedscription;

        public string FirstName { get { return _firstname; } set { _firstname = value;OnPropertyChanged("FirstName"); } }
        public string LastName { get { return _lastName; } set { _lastName = value; OnPropertyChanged("LastName"); } }
        public string Address { get { return _address; } set { _address = value; OnPropertyChanged("Address"); } }
        public string Contact { get { return _contact; } set { _contact = value; OnPropertyChanged("Contact"); } }
        public string Description { get { return _dedscription; } set { _dedscription = value; OnPropertyChanged("Description"); } }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string PropertyName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
    }



以下是ViewModel代码


Below is ViewModel Code

public  class ViewModel
 {
     MyDemoServiceReference.ModelEntity objentity;
     public ObservableCollection<Model.ModelEntity> obsColl { get; set; }
     MyDemoServiceReference.MyDemoServiceClient objservice = new MyDemoServiceReference.MyDemoServiceClient();
     public ModelEntity objmodel { get; set; }
     public ViewModel()
     {
        // obsColl = new ObservableCollection<ModelEntity>();
         // objentity = new MyDemoServiceReference.ModelEntity();
         objmodel = new ModelEntity();
         AddUser = new RelayCommand(SaveData);
     }
     public RelayCommand AddUser { get; set; }
     public RelayCommand UpdateUser { get; set; }



     void SaveData(object parameter)
     {

         // ModelEntity objmodel = new ModelEntity();
         // MyDemoServiceReference.ModelEntity objentity = new MyDemoServiceReference.ModelEntity();

         objentity.FirstName = objmodel.FirstName;
         if (objservice.SaveData(objentity))
             MessageBox.Show("Data Inserted");
         else
             MessageBox.Show("Data Not Inserted");

     }
 }





以下是Xmal Code





Below is Xmal Code

<Window x:Class="WPFDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:Model="clr-namespace:WPFDemo.Model"
        xmlns:viewmodel="clr-namespace:WPFDemo.ViewModel"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
 
    <Border Background="Chocolate" BorderThickness="1">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
            <TextBox Grid.Row="0" Height="50" Width="150" Text="{Binding ModelEntity.FirstName ,Mode=TwoWay}"  Grid.Column="1"></TextBox>
            <TextBox Grid.Row="1" Height="50" Width="150" Text="{Binding ModelEntity.LastName,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <TextBox Grid.Row="2" Height="50" Width="150" Text="{Binding ModelEntity.Address,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <TextBox Grid.Row="3" Height="50" Width="150" Text="{Binding ModelEntity.Contact,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <TextBox Grid.Row="4" Height="50" Width="150" Text="{Binding ModelEntity.Description,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <Label Grid.Row="0" Height="50" Width="150" Content="FirstName" Grid.Column="0"></Label>
            <Label Grid.Row="1" Height="50" Width="150" Content="LastName" Grid.Column="0"></Label>
            <Label Grid.Row="2"  Height="50" Width="150" Content="Address" Grid.Column="0"></Label>
            <Label Grid.Row="3" Height="50" Width="150" Content="Contact" Grid.Column="0"></Label>
            <Label Grid.Row="4"  Height="50" Width="150" Content="Description" Grid.Column="0"></Label>
            <Button Content="Save" Grid.Row="5" Grid.Column="2" Command="{Binding Path=AddUser}"  Height="50" Width="100"></Button>
        </Grid>
   </Border>
</Window>

推荐答案

首先,你的MVVM结构是向后的。应该更像这样:



First, your MVVM construct is ass-backwards. It should be more like this:

public class Model
{
    public string Prop1 { get; set; }

    public Model()
    {
    }

    public void GetData()
    {
        try
        {
            // retrieve the data from the datasource
            // populate this object with the retrieved data
        }
        catch (Exception ex)
        {
            // handle exception here
        }
    }

    public void SaveData
    {
        try
        {
            // save the data to the datasource
        }
        catch (Exception ex)
        {
            // handle exception here
        }
    }
}

public class ViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    // INotifyPropertyChanged implementation code goes here

    // IDataErrorInfo code goes here

    private string prop1;

    public string Prop1 
    { 
        get { return this.prop1; }
        set
        {
            if (value != this.prop1)
            {
                this.prop1 = value;
                this.NotifyPropertyChanged();
            }
        }
    }

    public ViewModel()
    {
        Model model = new Model();
        model.GetData();
        this.Prop1 = model.prop1;
    }
}


public class Window
{
    public ViewModel vm { get; set; }

    public Window()
    {
        this.InitializeComponents();
        this.DataContext = this;
        this.vm = new ViewModel();
    }
}





此时,您可以绑定到 vm.Prop1 在您的XAML中。



这是一个方便的类,我编写并使用从继承的所有时间INotifyPropertyChanged IDataErrorInfo 。我写它是为了兼容新版本和旧版本的.Net。这应该可以减轻一些实现ViewModel类的痛苦。只需在你自己的对象中继承它。





At that point, you can bind to vm.Prop1 in your XAML.

Here's a handy class that I wrote and use all the time that inherits from both INotifyPropertyChanged and IDataErrorInfo. I wrote it to be compatible with new and older versions of .Net. This should ease the pain a little of implementing ViewModel classes. Just inherit it in your own objects.

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfCommon
{
	/// <summary>
	/// Base class for all objects that require notifiablity and data validation
	/// </summary>
	public class Notifiable : INotifyPropertyChanged, IDataErrorInfo
	{
		#region INotifyPropertyChanged

		/// <summary>
		/// Occurs when a property value changes.
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

#if _NET_45_
		/// <summary>
		/// Notifies that the property changed, and sets IsModified to true.
		/// </summary>
		/// <param name="propertyName">Name of the property.</param>
        protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
				if (propertyName != "IsModified")
				{
					this.IsModified = true;
				}
            }
        }
#else
		/// <summary>
		/// Notifies that the property changed, and sets IsModified to true.
		/// </summary>
		/// <param name="propertyName">Name of the property.</param>
        protected virtual void NotifyPropertyChanged(String propertyName = "")
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
				if (propertyName != "IsModified")
				{
					this.IsModified = true;
				}
            }
        }
#endif
		#endregion INotifyPropertyChanged

		#region IDataErrorInfo Code

		/// <summary>
		/// Gets an error message indicating what is wrong with this object.
		/// </summary>
		public string Error
		{
			get { return "Error"; }
		}

		/// <summary>
		/// Gets the error message for the property with the given name.
		/// </summary>
		/// <param name="columnName">Name of the column.</param>
		/// <returns>The generated error message (if any).</returns>
		public string this[string columnName]
		{
			get 
			{
				return Validate(columnName);
			}
		}

		/// <summary>
		/// Validates the specified propery.
		/// </summary>
		/// <param name="properyName">Name of the propery.</param>
		/// <returns>Empty string if valid, otherwise, appropriate error message.</returns>
		protected virtual string Validate(string propertyName)
		{
			//Retun error message if there is error, otherwise return empty string
			string validationMsg = string.Empty;
			return validationMsg;
		}

		#endregion IDataErrorInfo Code

		#region Fields

		private bool isModified;
		private bool isSelected;
		private bool isVisible;
		private bool isEnabled;
		private bool isNew;
		private bool isClone;
		private bool isDeleted;
		private bool isValid;

		#endregion Fields

		#region Properties

		/// <summary>
		/// Gets or sets a value indicating whether this instance is modified.
		/// </summary>
		public virtual bool IsModified
		{
			get { return this.isModified; }
			set
			{
				if (this.isModified != value)
				{
					this.isModified = value;
					this.NotifyPropertyChanged("IsModified");
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is selected.
		/// </summary>
		public virtual bool IsSelected
		{
			get { return this.isSelected; }
			set
			{
				if (this.isSelected != value)
				{
					this.isSelected = value;
					this.NotifyPropertyChanged("IsSelected");
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is visible.
		/// </summary>
		public virtual bool IsVisible
		{
			get { return this.isVisible; }
			set
			{
				if (value != this.isVisible)
				{
					this.isVisible = value;
					this.NotifyPropertyChanged("IsVisible");
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is enabled.
		/// </summary>
		public virtual bool IsEnabled
		{
			get { return this.isEnabled; }
			set
			{
				if (value != this.isEnabled)
				{
					this.isEnabled = value;
					this.NotifyPropertyChanged("IsEnabled");
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is new.
		/// </summary>
		public virtual bool IsNew
		{
			get { return this.isNew; }
			set
			{
				if (value != this.isNew)
				{
					this.isNew = value;
					this.NotifyPropertyChanged("IsNew");
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is a clone of an existing object.
		/// </summary>
		public virtual bool IsClone
		{
			get { return this.isClone; }
			set
			{
				if (value != this.isClone)
				{
					this.isClone = value;
					this.NotifyPropertyChanged("IsClone");
				}
			}
		}
		/// <summary>
		/// Get/set the flag indicating whether or not this item is marked for delete.
		/// </summary>
		public virtual bool IsDeleted
		{
			get { return this.isDeleted; }
			set
			{
				if (value != this.isDeleted)
				{
					this.isDeleted = value;
					this.NotifyPropertyChanged("IsDeleted");
				}
			}
		}

		/// <summary>
		/// Get or set a flag indicating whether or not this item has an error
		/// </summary>
		public virtual bool IsValid
		{
			get { return this.isValid; }
			set
			{
				if (value != this.isValid)
				{
					this.isValid = value;
					this.NotifyPropertyChanged("IsValid");
				}
			}
		}

		#endregion Properties

		#region Constructor

		/// <summary>
		/// Initializes a new instance of the <see cref="Notifiable"/> class.
		/// </summary>
		public Notifiable(bool isNew=false)
		{
			this.IsNew      = isNew;
			this.IsModified = false;
			this.IsVisible  = true;
			this.IsEnabled  = true;
			this.isValid    = true;
			this.IsClone    = false;
			this.IsDeleted  = false;
		}

		#endregion Constructor
	}
}


让我们这样试试吧。



0)模型中不应包含通知代码。它只应该加载和保存数据。就是这样。



1)视图模型是模型中数据与视图的接口。它负责将数据操作为一种形式,使视图更容易使用。视图模型应继承 INotifyPropertyChanged 接口,并实现所需的方法和属性。可选地,它还应该继承 IDataErrorinfo 接口,但仅在您想要执行验证时才需要。您的UI应绑定到视图模型。



2)当您在窗体/控件中实例化视图模型时,请确保将其定义为公共。如果你不这样做,绑定*将不会*工作。



3)不要忘记设置你的 DataContext 在表单/控件中。大多数时候,我只是在表单/控件的构造函数中设置 this.DataContext = this 。您还可以在表单中设置单个控件的 DataContext 元素,但这很难以维护。



4)我在之前的回答中提供了一个类,你可以继承它,它可以完成 INotifyPropertyChanged 的所有令人讨厌的工作,而不必弄乱你的视图模型类。您还可以使用UI元素继承该类。



5)我建议您重构代码以遵循我在第一个答案中概述的最佳实践。您会发现分离问题要容易得多,它将使您不必在此处发布有关简单概念的问题。
Let's try it this way.

0) The model is not supposed to have notification code in it. It's only supposed to load and save the data. That's it.

1) The view model is where you interface the data in the model with the view. It's responsible for manipulating the data into a form that makes it easier for the view to use. The view model should inherit the INotifyPropertyChanged interface, and implement the required methods and properties. Optionally, it should also inherit the IDataErrorinfo interface, but is only necessary if you want to perform validation. Your UI should bind to the view model.

2) When you instantiate your view model in the form/control, make sure you define it as public. If you don't, binding *will not* work.

3) Don't forget to set your DataContext in the form/control. Most of the time, I simply set this.DataContext = this in the constructor of the form/control. You can also set the DataContext element of a individual controls in the form, but that's a pain and can be difficult to maintain.

4) I provided a class in my previous answer that you can inherit that does all the nasty work of INotifyPropertyChanged without having to clutter your view model classes. You can also inherit the class with UI elements.

5) I recommend that you refactor your code to follow the best practice I outlined in my first answer. You will find it much easier to separate concerns, and it will keep you from having to post questions here about simple concepts.


我得到了解决方案..

I got solution..
public  class EmpViewModel: INotifyPropertyChanged
   {
       MyDemoServiceReference.ModelEntity objentity;
       private ObservableCollection<Model.ModelEntity> obsColl { get; set; }
       MyDemoServiceReference.MyDemoServiceClient objservice = new MyDemoServiceReference.MyDemoServiceClient();
       public ModelEntity objmodel { get; set; }
       public EmpViewModel()
       {
           AddUser = new Command(AddCanExuteMethod, AddExuteMethod);
           obsColl = new ObservableCollection<Model.ModelEntity>();
           // objentity = new MyDemoServiceReference.ModelEntity();
           objmodel = new ModelEntity();

       }
       public ICommand AddUser { get; set; }
       public ICommand UpdateUser { get; set; }
     public ObservableCollection<Model.ModelEntity> Objmodel
       {
           get
           {
               return obsColl;
           }
           set
           {
               obsColl = value;
               OnPropertyChanged("Objmodel");
           }
       }
       public bool AddCanExuteMethod(object parameter)
       {
           return true;
       }
       public void AddExuteMethod(object parameter)
       {
           objentity = new MyDemoServiceReference.ModelEntity();
           objentity.FirstName = objmodel.FirstName;
           if (objservice.SaveData(objentity))
           {
               MessageBox.Show("Data Inserted");

           }
           else
           {
               MessageBox.Show("Data Not Inserted");
           }


       }
       void SaveData(object parameter)
       {


           // ModelEntity objmodel = new ModelEntity();
           // MyDemoServiceReference.ModelEntity objentity = new MyDemoServiceReference.ModelEntity();

           objentity.FirstName = objmodel.FirstName;
           if (objservice.SaveData(objentity))
               MessageBox.Show("Data Inserted");
           else
               MessageBox.Show("Data Not Inserted");

       }

       public event PropertyChangedEventHandler PropertyChanged;
       public void OnPropertyChanged(string PropertyName)
       {
           if (PropertyChanged != null)
           {
               PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
           }
       }
   }





我的Xaml代码是



My Xaml Code is

<Window x:Class="WPFDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:local="clr-namespace:WPFDemo.Model"
        xmlns:viewmodelVm="clr-namespace:WPFDemo.ViewModel"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    
<Border Background="Chocolate" BorderThickness="1">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
            <TextBox Grid.Row="0" Height="50" Width="150" Text="{Binding objmodel.FirstName ,Mode=TwoWay}"  Grid.Column="1"></TextBox>
            <TextBox Grid.Row="1" Height="50" Width="150" Text="{Binding objmodel.LastName,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <TextBox Grid.Row="2" Height="50" Width="150" Text="{Binding objmodel.Address,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <TextBox Grid.Row="3" Height="50" Width="150" Text="{Binding objmodel.Contact,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <TextBox Grid.Row="4" Height="50" Width="150" Text="{Binding Description,Mode=TwoWay}" Grid.Column="1"></TextBox>
            <Label Grid.Row="0" Height="50" Width="150" Content="FirstName" Grid.Column="0"></Label>
            <Label Grid.Row="1" Height="50" Width="150" Content="LastName" Grid.Column="0"></Label>
            <Label Grid.Row="2"  Height="50" Width="150" Content="Address" Grid.Column="0"></Label>
            <Label Grid.Row="3" Height="50" Width="150" Content="Contact" Grid.Column="0"></Label>
            <Label Grid.Row="4"  Height="50" Width="150" Content="Description" Grid.Column="0"></Label>
            <Button Content="Save" Grid.Row="5" Grid.Column="2" Command="{Binding Path=AddUser}"  Height="50" Width="100"></Button>
        </Grid>
   </Border>
</Window>


这篇关于如何在MVVM模式中访问viewmodel中的文本框值?我的代码如下的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆