用于获取/设置viewmodel的文本框输入

时间:2014-08-19 17:29:37

标签: c# wpf mvvm viewmodel

我确信这已经被问到了,但我还是MVVM和WPF的新手,并且不太确定我应该搜索什么。

我有一个viewmodel,它包含Model中的项目,以及一些其他临时数据项,这些项目都将传递给process.start()。我有一个文本框的stackpanel,并希望允许用户键入" ModelName",如果存在,ViewModel将获取并设置" TemplateName"与ModelName相关联。

我对如何实现这一点感到有些失落。我是否需要创建一个完全独立的ViewModel,然后从ModelViewModel中提取数据?我只是在ModelName&#39s下编写一些代码,它可以验证,查询和设置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>

3 个答案:

答案 0 :(得分:2)

要让你的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 ='TwoWay'这会使GUI更改viewmodel中的值,而不是仅显示它们。因此,您需要在上面应该可编辑的所有内容上设置它。 WPF的默认行为是,当控件失去焦点时,它将更新绑定属性,如果设置UpdateSourceTrigger ='PropertyChanged',则每次更新属性,即在文本框中输入字母。我会把那部分留给你,但是你必须在你的vm中做到这一点!至少属性SONumber,SerialNumber和Models(如果它的引用更改)。

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

答案 1 :(得分:1)

如果我没有误解你的问题,请将模型绑定到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类的实例。

答案 2 :(得分:0)

您需要在绑定到的属性上引发属性更改事件,即:

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();