2013-07-07 4 views
1

Windows 형식으로이 작업을 만들려고했지만 wpf mvvm이 더 좋을 것이라고 들었습니다. 나는 C#에 익숙하지 않고 mvvm과 wpf를 연구하고있다.MVVM ViewModel 만들기 및 바인딩

이제 뷰와 모델 모두에서 작동하도록 내 viewmodel에서 작업하고 있습니다. 데이터베이스가 없습니다.


내 문제 : 나는 올바르게 뷰 모델에보기를 결합 어떻게

. 내 xaml 어딘가에 itemssource 또는 localsource 코드가 누락되었지만 itemsource 작동 방식을 이해하지 못합니다. viewmodel에서 선언 된 itemsource가 어디에 있는지. 좋은 답변을 찾기 위해 인터넷 검색을 해왔지만 아직 나를 클릭하는 링크를 찾지 못했습니다.

또한 INotifyChange 유형 속성이 있고 일부 코드 예제를 본 적이 있지만 완전히 이해하지는 않았으며 단지 나를 클릭하지 않았습니다. 현재


는 :

나는 첫 번째 코드 아래와 같습니다 XAML에서 만든 볼 수 있습니다. 그런 다음 C#에서 두 번째 코드 그룹 인 스캔을위한 클래스를 만들었습니다. get set 메서드는 개선 될 수 있지만 튜토리얼을 따라갔습니다.

스캔 건을 사용하는 사용자는 스캔 할 때 화면을 보지 않습니다. 첫 번째 텍스트 상자에 첫 번째 스캔 채우기 순서로 두 번째 텍스트 상자를 두 번째 스캔 채우고 필요할 경우 카운트를 채 웁니다.


추가 정보 :

하단 부분 (DataView를)는 이전의 스캔을 보여주기위한 임시 테이블입니다하지만 우리 나중에 있음을 알 수 있습니다. 가장 중요한 부분은 스캔을 가져와 그 (것)들과 무언가를 할 수 있다는 것입니다.

스캔은 keyboardwedge가 될 것입니다. (끝에서 Enter 키와 같은 문자를 전송합니다.) 나중에이 프로그램을 백그라운드에서 실행할 수 있도록 시리얼 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

스캔 클래스는 INotifyPropertyChanged에서 상속해야하며 각 인스턴스는 관찰 가능한 컬렉션에 있어야합니다. VM에서 생성되고 ListView 컨트롤의 항목 소스 속성에 바인딩되어야하는 관찰 가능한 컬렉션입니다. 스 니펫을 생성하는 C# 속성을 가져 오면 '스캔'클래스 리팩토링과 관련하여 수명을 절약 할 수 있습니다. –

답변

0

뷰의 DataContext로 뷰 모델 클래스의 인스턴스를 설정해야합니다.

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

     DataContext = new Scan(); 
    } 
} 

보기는 않는 변화를 감지 할 수 없습니다 것을 유의 사항 : 당신이 다음 할 것이다 당신의 MainWindow.xaml.cs를 그렇게 나는 보통, 뷰의 코드 숨김에서이 ​​작업을 수행 그것을 알리십시오.해당 속성에 바인딩 할 수 있습니다, 당신의 MainWindow.xaml에서

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"); } 
    } 
} 

: 즉,에서 INotifyPropertyChanged 인터페이스의 요점은 OperatorCode에 대한 새 값을 설정할 때마다 지금

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

,보기가 될 것입니다 새로운 값을 가져 와서 표시 할 수 있도록 알려줍니다.

ItemsSources의 경우 IEnumerable은 List, 배열 ... 그러나 컬렉션이 변경 될 때마다보기를 알리려면 ObservableCollection과 같이 INotifyCollectionChanged를 구현하는 클래스를 사용해야합니다. .

그래서, 당신은 당신의 뷰 - 모델에 바인딩 속성을 만들 :

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

그리고 당신은보기 내에서 그 바인딩 :

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

마이너 점

: C#에서 클래스 이름은 보통 CamelCase로 작성되었습니다. 또한 필자는 개인적으로 각 View-Model 클래스에 ViewModel 후위를 부여하는 것을 선호하므로 어떤 클래스가 뷰 모델이 될 것인지를 신속하게 확인할 수 있습니다. 나는 그들의 이름을 그들이 속한 뷰의 이름과 일치 시키려고 시도한다. 그래서 'scan'대신 'MainWindowViewModel'이라고 부를 것이다.

+0

Pieter, 고맙습니다. 이것은 좋은 출발점입니다. 당신의 작은 의견들 대부분은 제가 다른 대부분의 읽기에서 빠졌던 것을 모았습니다. – BrinkDaDrink

0

코드가 너무 자바와 같은 있기 때문에 당신은 어떤 WPF의 UI 요소에 그 중 하나를 바인딩 할 수 없습니다.

Properties C# 방식을 사용해야합니다.

모든 get()set() 방법을 실제 속성으로 변경하십시오.

+0

HighCore에 감사드립니다. 나는 그들을 올바르게 바꿨다. – BrinkDaDrink