获取/设置视图模型的文本框输入
本文关键字:文本 输入 模型 设置 视图 获取 | 更新日期: 2023-09-27 18:18:38
我相信已经有人问过这个问题了,但我仍然是MVVM和WPF的新手,不太确定我应该搜索什么。
我有一个视图模型,其中包括模型中的项,以及一些额外的临时数据项,这些数据项都将传递给process.start()。我有一个文本框的堆栈面板,并希望允许用户输入一个"ModelName",如果存在,ViewModel将获得并设置与ModelName关联的"TemplateName"。
我有点迷失在如何实现这一点。我是否需要创建一个完全独立的ViewModel,然后从ModelViewModel提取数据?我只是在ModelName的集合下编写一些代码,在那里它可以验证、查询和设置TemplateName吗?
模型:
public partial class Model
{
public string ModelName { get; set; }
public virtual Template Template { get; set; }
和ViewModel,后者接受Model和一些临时数据:
public class LauncherViewModel:ViewModelBase
{
public LauncherViewModel()
{
_ESTContext = new ESTContext();
Models = new ObservableCollection<Model>(_ESTContext.Models);
}
private ESTContext _ESTContext;
private string _modelname;
private string _serialno;
private string _sonumber;
private string _templatename;
private string _outputname;
private Model _selectedmodel;
public ObservableCollection<Model> Models { get; set; }
public string ModelName
{
get { return _modelname; }
set
{
if (!string.Equals(_modelname, value))
{
_modelname = value;
};
}
}
public string TemplateName { get { return _templatename; }}
public string SerialNo { get { return _serialno; } }
public string SONumber { get { return _sonumber; } }
public string OutputName { get { return _outputname; } }
public Model SelectedModel
{
get { return _selectedmodel; }
set
{
if (_selectedmodel != value)
{
_selectedmodel = value;
}
}
}
}
我的观点:
<DockPanel>
<StackPanel Margin="0,78,0,68" Width="233" DataContext="{Binding Models}">
<ComboBox IsEditable="True" Text="{Binding ModelName}" SelectedItem="{Binding SelectedModel}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SONumber}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SerialNumber}"/>
<Button Content="Button"/>
</StackPanel>
</DockPanel>
对于你的gui更新你必须实现INotifyPropertyChanged和调用它对你所有的绑定属性。
// basic base class for your models, you a
public class ModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] // remove if you are not using R#
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
// your model
public class Model : ModelBase
{
private string modelName;
private Template template;
public string ModelName
{
get { return modelName; }
set
{
if (value == modelName) return;
modelName = value;
OnPropertyChanged();
}
}
public virtual Template Template
{
get { return template; }
set
{
if (Equals(value, template)) return;
template = value;
OnPropertyChanged();
}
}
}
视图:
<DockPanel>
<StackPanel Margin="0,78,0,68" Width="233">
<ComboBox IsEditable="True" Text="{Binding ModelName, Mode='TwoWay'}" SelectedItem="{Binding SelectedModel}" ItemsSource="{Binding Models}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SONumber Mode='TwoWay'}"/>
<TextBox Height="23" TextWrapping="Wrap" Text="{Binding SerialNumber Mode='TwoWay'}"/>
<Button Content="Button"/>
</StackPanel>
注意Mode=' two - way ',这会使GUI更改视图模型中的值,而不仅仅是显示它们。所以你需要像上面那样在所有应该是可编辑的东西上设置这个。WPF的默认行为是,当控件失去焦点时,它将更新绑定的属性,如果设置UpdateSourceTrigger='PropertyChanged',则每次在文本框中输入字母时,属性都会更新。我将把这部分留给你,但你必须在你的vm中完成!至少属性number,SerialNumber和Models(如果是ref. changes)。
VM:我假设你在这里使用galasoft
public class LauncherViewModel : ViewModelBase
{
private ESTContext _ESTContext;
private string _templatename;
private string _modelname;
private string serialNumber;
private string _outputname;
private string modelName;
private ObservableCollection<Model> models;
private Model selectedModel;
private string soNumber;
public LauncherViewModel()
{
// dangerous ;)
_ESTContext = new ESTContext();
Models = new ObservableCollection<Model>(_ESTContext.Models);
}
public ObservableCollection<Model> Models
{
get { return models; }
set
{
if (Equals(value, models)) return;
models = value;
RaisePropertyChanged();
}
}
public string ModelName
{
get { return modelName; }
set
{
if (value == modelName) return;
modelName = value;
RaisePropertyChanged();
}
}
public string TemplateName { get { return _templatename; }}
public string SerialNumber // Note you spelled this wrong in your xaml. SONumber
{
get { return serialNumber; }
set
{
if (value == serialNumber) return;
serialNumber = value;
RaisePropertyChanged();
}
}
public string SONumber
{
get { return soNumber; }
set
{
if (value == soNumber) return;
soNumber = value;
RaisePropertyChanged();
}
}
public string OutputName { get { return _outputname; } }
public Model SelectedModel
{
get { return selectedModel; }
set
{
if (Equals(value, selectedModel)) return;
selectedModel = value;
RaisePropertyChanged();
}
}
}
如果你将galasoft或sim与r#一起使用,这是一个很酷的小事情。
public class YourViewModelBase : ViewModelBase
{
[NotifyPropertyChangedInvocator] // alt + enter = convert auto property to prop
// with backing field and change notification :)
override protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
base.RaisePropertyChanged(propertyName);
}
// .. :)
}
欢呼,
Stian
如果我没有误解你的问题,将模型绑定到ComboBox的ItemsSource而不是将其绑定到StackPanel的DataContext
删除DataContext绑定
<StackPanel Margin="0,78,0,68" Width="233" >
将ComboBox的Itemssource绑定到Models,你还必须指定DisplayMemberPath到你想在ComboBox中显示的Model的属性。
<ComboBox IsEditable="True" ItemsSource="{Binding Models}" Text="{Binding ModelName}" SelectedItem="{Binding SelectedModel}"/>
我假设你正在设置窗口的DataContext到LauncherViewModel类的实例
你需要在你绑定的属性上引发property changed事件,即:
private string _ModelName;
public string ModelName
{
get { return _ModelName; }
set
{
if (_ModelName != value)
{
_ModelName = value;
RaisePropertyChanged("ModelName");
}
}
}
在你的基本视图模型中,你需要这样的东西(确保你实现了INotifyPropertyChanged):
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
在视图的构造函数或加载事件中添加:
DataContext = new LauncherViewModel();