Member 10310320 Ответов: 3

Как получить доступ к значению текстового поля в viewmodel в шаблоне MVVM? Мой код выглядит следующим образом


Я новичок в MVVM, моя проблема в том, что я не могу получить доступ к значению текстового поля MainWindow(View) в ViewModel.

Что я уже пробовал:

Это свойства модели
<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
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

<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>

Kenneth Haugland

Я ослеп, или вы забыли установить DataContext?

Member 10310320

Вот он
пространство имен WPFDemo
{
/// & lt;резюме>
/// Логика взаимодействия для MainWindow. xaml
///
публичный частичный класс MainWindow: Window
{
публичное главное окно()
{
метод InitializeComponent();
этот.DataContext = новая модель представления.модель представления();

}
}
}

Kenneth Haugland

Что ж, это верно,но на что вы здесь жалуетесь? Обычно я бы отправил некоторые командные параметры с нажатием кнопки, это то, о чем вы спрашиваете?

Member 10310320

В этой функции
void SaveData(параметр объекта)
{

// ModelEntity objmodel = новая модель();
// MyDemoServiceReference.ModelEntity objectity = новый MyDemoServiceReference.Модельность();

объективность.Имя = objmodel.имя;
if (objservice.SaveData(objectity))
Ящик для сообщений.Показать("Сведения Вставлен");
ещё
Ящик для сообщений.Show ("Данные Не Вставлены");

}
Я не получаю значение текстового поля, то есть имя
или различный контроль также

#realJSOP

Серьезно? Вы проголосовали против единственного ответа, который вы получили до сих пор от кого-то с большим опытом работы в WPF, чем у вас в отрасли?

Member 10310320

Он просто объяснил новый подход. Но моя проблема остается прежней.

3 Ответов

Рейтинг:
5

Member 10310320

У меня есть решение..

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 является
<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>


Рейтинг:
1

#realJSOP

Во-первых, ваша конструкция MVVM задом наперед. Это должно быть больше похоже на это:

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. Просто унаследуйте его в своих собственных объектах.

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

#realJSOP

Давайте попробуем так.

0) модель не должна иметь в себе код уведомления. Он должен только загружать и сохранять данные. Вот и все.

1) модель представления - это место, где вы взаимодействуете данные в модели с представлением. Он отвечает за манипулирование данными в форме, которая облегчает использование представления. Модель представления должна наследовать INotifyPropertyChanged интерфейс, а также реализовать необходимые методы и свойства. При желании он также должен наследовать IDataErrorinfo интерфейс, но необходим только в том случае, если вы хотите выполнить проверку. Ваш пользовательский интерфейс должен быть привязан к модели представления.

2) Когда вы создаете экземпляр модели представления в форме / элементе управления, убедитесь, что вы определили ее как public. Если вы этого не сделаете, привязка *не будет* работать.

3) Не забудьте установить свой DataContext в форме / контроле. Большую часть времени, я просто установить this.DataContext = this в конструкторе формы / элемента управления. Вы также можете установить DataContext элемент индивидуального контроля в форме, но это боль и может быть трудно поддерживать.

4) в своем предыдущем ответе я предоставил класс, который вы можете унаследовать и который выполняет всю неприятную работу INotifyPropertyChanged без необходимости загромождать классы моделей представлений. Вы также можете наследовать класс с элементами пользовательского интерфейса.

5) я рекомендую вам реорганизовать свой код, чтобы следовать лучшей практике, которую я изложил в своем первом ответе. Вам будет гораздо легче отделить проблемы, и это избавит вас от необходимости задавать здесь вопросы о простых концепциях.


Member 10310320

Это мой модельный код
публичный класс ModelEntity:INotifyPropertyChanged
{
публичная модель()
{ }
частная строка _firstname;
частная строка _lastName;
частная строка _address;
частная строка _contact;
частная строка _dedscription;

общественного строка имя { получить { возвращение _firstname; } набор { _firstname = значение;PropertyChang("имя"); } }
общественного строка имя { получить { возвращение _lastName; } набор { _lastName = значение; PropertyChang("фамилия"); } }
общественного строка адреса { get { возвращение _address; } набор { _address = значение; PropertyChang("адрес"); } }
общественного строка контактов { get { возвращение _contact; } набор { _contact = значение; PropertyChang("контакт"); } }
общественного строка описание { get { возвращение _dedscription; } набор { _dedscription = значение; PropertyChang("описание"); } }

публичное мероприятие PropertyChangedEventHandler PropertyChanged;
общественного недействительными PropertyChang(строку Имя_свойства)
{
if (PropertyChanged!=null)
{
PropertyChanged (this, new PropertyChangedEventArgs(PropertyName));
}
}
}