1

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

我现在正在研究我的视图模型以同时使用视图和模型。没有数据库。


我的问题:

如何正确地将视图绑定到视图模型。我在我的 xaml 中的某处缺少 itemssource 或 localsource 代码,但我也不明白 itemsource 是如何工作的。在视图模型中声明的 itemsource 以及如何声明的位置。我一直在寻找一个好的答案,但仍然没有找到一个让我点击的答案。

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


目前:

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

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


额外信息:

底部(数据视图)是一个临时表,用于显示以前的扫描,但我可以稍后再计算。最重要的部分是能够进行扫描并对其进行处理。

扫描将是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;
        }
    }
}
4

2 回答 2

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 都可以 - 一个列表、一个数组……但是,如果您希望在集合更改时通知视图,则必须使用实现 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”,而不是“扫描”。

于 2013-07-07T20:42:57.463 回答
0

您不能将其中的任何内容绑定到任何 WPF UI 元素,因为您的代码太像 java。

您需要使用C# 方式的属性。

将您的所有get()set()方法更改为真实属性。

于 2013-07-07T17:19:48.203 回答