MVVM ViewModel创建和绑定

时间:2013-07-07 15:13:22

标签: c# wpf mvvm

我打算使用Windows窗体创建它,但被告知wpf mvvm会更好。我是c#的新手,一直在研究mvvm和wpf。

我现在正在使用我的viewmodel来处理视图和模型。没有数据库。


我的问题:

如何正确地将视图绑定到viewmodel。我在我的xaml中遗漏了一个itemssource或localsource代码,但我也不明白itemsource是如何工作的。 viewmodel中的哪个是声明的itemsource以及如何。我一直在谷歌搜索一个很好的答案,但仍然没有找到一个让它为我点击。

我也知道有一个INotifyChange类型的属性,我已经看到了一些代码示例但是没有完全理解它,它只是没有点击给我。


目前:

我在xaml中创建了一个视图,这是下面的第一个代码。然后我创建了一个扫描类,这是c#中的第二组代码(我知道get set方法可以改进,但我正在学习教程)。

使用扫描枪的用户在扫描时不会看屏幕。我希望能够按顺序进行,因此首先扫描填充第一个文本框,第二个扫描填充第二个文本框,如果需要,他们将填写计数。


额外信息:

底部(dataview)是一个用于显示先前扫描的临时表,但我可以在后面看到。最重要的部分是能够获得扫描并对它们做些什么。

扫描将是keyboardwedge(发送字符就像输入键一样输入键)但稍后我打算将它们设置为串行com端口,以便该程序可以在后台运行。

注意:我知道我提供了很多详细信息,这些信息可能不是小电流问题所必需的,但只是想明确。

<Window x:Class="ScanningV2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="700">
    <DockPanel LastChildFill="True">
        <Grid x:Name="LayoutRoot" DockPanel.Dock="Top" Height="100" Background="#FFFFFF" Margin="2,2,2,2">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Button Grid.Row="0" Grid.Column="0" Content="Scan" Grid.ColumnSpan="1" Margin="2,2,2.2,2" />
            <Label Content="Operator Barcode" Grid.Column="1" HorizontalAlignment="Left" Margin="50,20,0,0" VerticalAlignment="Top" Width="120" />
            <Label Content="MO/Task Barcode" Grid.Column="1" HorizontalAlignment="Left" Margin="200,20,0,0" VerticalAlignment="Top" Width="120" />
            <Label Content="Quantity" Grid.Column="1" HorizontalAlignment="Left" Margin="350,20,0,0" VerticalAlignment="Top" Width="120" />
            <TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="50,50,0,0" TextWrapping="Wrap" Text="Scan" VerticalAlignment="Top" Height="20" Width="120" />
            <TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="200,50,0,0" TextWrapping="Wrap" Text="Scan" VerticalAlignment="Top" Height="20" Width="120" />
            <TextBox Grid.Column="1" HorizontalAlignment="Left" Margin="350,50,0,0" TextWrapping="Wrap" Text="Scan" VerticalAlignment="Top" Height="20" Width="120" />

            <!--            <ListView Grid.Row="0" Grid.Column="1" x:Name="curScans" Background="Aqua" Grid.ColumnSpan="1" Margin="1.8,0,-0.4,0">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Scanner" DisplayMemberBinding="{Binding Path=curScanNum}" Width="150" />
                        <GridViewColumn Header="Operator" DisplayMemberBinding="{Binding Path=curOperator}" Width="200" />
                        <GridViewColumn Header="Task" DisplayMemberBinding="{Binding Path=curTask}" Width="200"/>
                    </GridView>
                </ListView.View>
            </ListView> -->
        </Grid>
        <ListView x:Name="pastScans" Background="#2FFFFFFF" DockPanel.Dock="Bottom">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Scanner" DisplayMemberBinding="{Binding Path=ScannerNum}" Width="100" />
                    <GridViewColumn Header="Operator barcode" DisplayMemberBinding="{Binding Path=Operator}" Width="150" />
                    <GridViewColumn Header="MO/Task barcode" DisplayMemberBinding="{Binding Path=Task}" Width="150" />
                    <GridViewColumn Header="Date" DisplayMemberBinding="{Binding Path=ScanDate}" Width="100" />
                    <GridViewColumn Header="Time" DisplayMemberBinding="{Binding Path=ScanTime}" Width="100" />
                    <GridViewColumn Header="Quantity" DisplayMemberBinding="{Binding Path=Quantity}" Width="100" />
                </GridView>
            </ListView.View>
        </ListView>

    </DockPanel>

</Window>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ScanningV2
{
    class scan
    {
        //Member variables
        private string operatorCode;
        public string OperatorCode
        {
            get { return operatorCode; }
            set { operatorCode = value; }
        }

        private string taskCode;
        public string TaskCode
        {
            get { return taskCode; }
            set { taskCode = value; }
        }

        private int count;
        public int Count
        {
            get { return count; }
            set { count = value; }
        }

        private DateTime scanDateTime;
        public DateTime ScanDateTime
        {
            get { return scanDateTime; }
            set { scanDateTime = value; }
        }

        //Default Constructor
        public scan()
        {
            operatorCode = null;
            taskCode = null;
            count = 0;
        }

        //Overload Constructor
        public scan(string OperCode, string TaskMOCode, int CountNum)
        {
            operatorCode = OperCode;
            taskCode = TaskMOCode;
            count = CountNum;
        }
    }
}

2 个答案:

答案 0 :(得分:0)

您无法将任何内容绑定到任何WPF UI元素,因为您的代码太像Java了。

您需要使用Properties C#方式。

将您的所有get()set()方法更改为不动产。

答案 1 :(得分:0)

您必须将视图模型类的实例设置为视图的DataContext。我通常在视图的代码隐藏中执行此操作,因此在MainWindow.xaml.cs中,您将执行以下操作:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = new Scan();
    }
}

请注意,除非您通知,否则您的视图将无法检测到更改。这就是INotifyPropertyChanged接口的重点:

class Scan : INotifyPropertyChanged
{
    // Implementing the INotifyPropertyChanged interface:
    public event PropertyChangedEventHandler PropertyChanged;

    // A utility method to make raising the above event a little easier:
    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    // Then, notify the view about changes whenever a property is set:
    private string operatorCode;
    public string OperatorCode
    {
        get { return operatorCode; }
        set { operatorCode = value; RaisePropertyChanged("OperatorCode"); }
    }
}

在MainWindow.xaml中,您可以绑定到该属性:

<TextBlock Text="{Binding OperatorCode}" />

现在,无论何时为OperatorCode设置新值,都会通知您的视图,以便它可以获取并显示新值。

对于ItemsSources,任何IEnumerable都可以 - 一个List,一个数组......但是,如果你希望在你的集合发生变化时通知视图,你将不得不使用一个实现INotifyCollectionChanged的类,比如ObservableCollection。

因此,您在视图模型中创建了一个可绑定属性:

private ObservableCollection<string> names;
public ObservableCollection<string> Names
{
    get { return names; }
    set { names = value; RaisePropertyChanged("Names"); }
}

你从视图中绑定到它:

<ListView ItemsSource="{Binding Names}" />

小点:在C#中,类名通常用CamelCase编写。另外,我个人更喜欢为每个视图模型类提供一个ViewModel后缀,因此您可以快速查看哪些类是视图模型。我尝试将他们的名字与他们所属的视图的名称相匹配,因此我将其称为'MainWindowViewModel',而不是'scan'。