我打算使用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;
}
}
}
答案 0 :(得分:0)
答案 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'。