0

最初: MVVM と WPF は初めてです。

タブ付きのユーザー インターフェイスを備えた小さなアプリケーションを作成しようとしています。ユーザーは、新しい TabItem を開くボタンを使用して、製品と保管場所を作成できます。

ビュー内の私のコードは次のようになります。

<TabControl ItemsSource="{Binding Workspaces}"
        IsSynchronizedWithCurrentItem="True"
        Margin="3"
        DockPanel.Dock="Top">
  <TabControl.ItemTemplate>
       <DataTemplate>
          <Label Content="{Binding DisplayName}" />
       </DataTemplate>
  </TabControl.ItemTemplate>
</TabControl>

ビューモデルは次のとおりです。

ObservableCollection<WorkspaceViewModel> _workspaces;
    public ObservableCollection<WorkspaceViewModel> Workspaces
    {
        get
        {
            if (_workspaces == null)
            {
                _workspaces = new ObservableCollection<WorkspaceViewModel>();
            }
            return _workspaces;
        }
        set
        {
            _workspaces = value;

        }
    }
public void AddProduct(object obj)
    {
        Workspaces.Add(new ProductViewModel());
    }

その他のさまざまなボタンによって、さまざまな ViewModel がワークスペース コレクションに追加されます。

複数のデータ テンプレート (ViewModel ごとに 1 つ) を定義しました。これが1つです:

<DataTemplate DataType="{x:Type vm:ProductViewModel}">
    <vw:ProductView />
</DataTemplate>

WorkspaceViewModel は次のとおりです。

namespace Inventory.Desktop.ViewModels
{
public abstract class WorkspaceViewModel : INotifyPropertyChanged
{
    #region Events and EventHandlers

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion
}
}

たとえば、ProductViewModel

namespace Inventory.Desktop.ViewModels
{
public class ProductViewModel: WorkspaceViewModel
{
    private Product _product;
    private string _displayName;


    public string DisplayName
    {
        get
        {
            if (String.IsNullOrEmpty(_displayName))
            {
                return "Neues Produkt";
            } else
            {
                return _displayName;
            }
        }
        set
        {
            _displayName = value;
            NotifyPropertyChanged("DisplayName");
        }
    }


    #region Public Properties

    public Product Product
    {
        get
        { 
            return _product; 
        }
        set
        {
            _product = value;
            NotifyPropertyChanged("Product");
        }
    }

    public string Title
    {
        get
        {
            return _product.Title;
        }
        set
        {
            _product.Title = value;
            NotifyPropertyChanged("Title");
        }
    }

    public string ScanCode
    {
        get
        {
            return _product.ScanCode;
        }
        set
        {
            _product.ScanCode = value;
            NotifyPropertyChanged("ScanCode");
        }
    }

    public string Manufacturer
    {
        get
        {
            return _product.Manufacturer;
        }
        set
        {
            _product.Manufacturer = value;
            NotifyPropertyChanged("Manufacturer");
        }
    }

    public string ManufacturerNumber
    {
        get
        {
            return _product.ManufacturerNumber;
        }
        set
        {
            _product.ManufacturerNumber = value;
            NotifyPropertyChanged("ManufacturerNumber");
        }
    }

    public string Description
    {
        get
        {
            return _product.Description;
        }
        set
        {
            _product.Description = value;
            NotifyPropertyChanged("Description");
        }
    }

    #endregion

    #region Commands

    private ICommand _saveCommand;

    public ICommand SaveCommand
    {
        get
        {
            return _saveCommand;
        }
        set
        {
            _saveCommand = value;
        }
    }

    #endregion

    #region Command Executions

    public void Save(object obj)
    {

        using (var db = new InvContext())
        {
            db.Products.Attach(Product);
            db.Entry(Product).State = Product.ProductId == 0 ?
                EntityState.Added : EntityState.Modified;
            db.SaveChanges();
        }

        MessageBox.Show("Product saved: " + Product.Title);
    }

    #endregion

    #region Constructors

    public ProductViewModel()
    {
        if (_product == null)
        {
            _product = new Product();
        }

        SaveCommand = new RelayCommand(new Action<object>(Save));
    }

    #endregion


}
}

ここでProductView.xamlビュー:

<UserControl x:Class="Inventory.Desktop.Views.ProductView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="400" d:DesignWidth="450">
<DockPanel>
    <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" FlowDirection="RightToLeft">
        <Button Name="SaveProductButton" Command="{Binding SaveCommand}" Content="Speichern" Margin="3" BorderThickness="0">
        </Button>
    </StackPanel>
    <StackPanel DockPanel.Dock="Top" VerticalAlignment="Stretch">
        <Label Content="Scan Code" />
        <TextBox Text="{Binding Path=ScanCode}" HorizontalAlignment="Stretch" Margin="3" Padding="3" Height="50" TextAlignment="Right">
            <TextBox.Background>
                <ImageBrush ImageSource="..\Images\Barcode32.png" AlignmentX="Left" Stretch="None" />
            </TextBox.Background>
        </TextBox>
        <Label Content="Bezeichnung" />
        <TextBox Text="{Binding Path=Title, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" Margin="3" />
        <Label Content="Hersteller" />
        <TextBox Text="{Binding Path=Manufacturer, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" Margin="3" />
        <Label Content="Hersteller Nummer" />
        <TextBox Text="{Binding Path=ManufacturerNumber, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" Margin="3" />
        <Label Content="Beschreibung / Information" />
        <TextBox Text="{Binding Path=Description, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" Margin="3" />
    </StackPanel>

</DockPanel>
</UserControl>

そしてここにコードビハインドProductView.xaml.cs

namespace Inventory.Desktop.Views
{
/// <summary>
/// Interaktionslogik für ProductView.xaml
/// </summary>
public partial class ProductView : UserControl
{

    ProductViewModel _productModel = new ProductViewModel();

    public ProductView()
    {
        InitializeComponent();
        base.DataContext = _productModel;
    }
}
}

現在動作しているもの:

  • ボタンをクリックすると、正しいビューを表示する新しい TabItem が表示され、すべてのコマンドが正しく機能します。

機能していないもの:

  • TabItem を開いて情報を入力し、別の ViewModel で別の TabItem を開いて、フォーカスを新しい TabItem に切り替えてから元のオブジェクトに戻すと、入力したすべての情報が失われます (オブジェクトは null です)。

  • TabItem を開いて情報を入力し、同じ ViewModel で別の TabItem を開くと、両方の TabItem に同じ情報が表示されます。

  • 新しい TabItem を追加すると、フォーカスが得られません。

私は完全に迷っており、私が間違っていることを教えていただければ幸いです。

一番

ステファン

4

1 に答える 1

1

現在/選択されているタブへの参照を格納するために、ViewModel にプロパティを設定します。

public WorkspaceViewModel SelectedTab
{
    get { return _selectedTab; }
    set
    {
        _selectedTab = value;
        RaisePropertyChanged(() => SelectedTab);
    }
}

これをSelectedItemTabControl のプロパティにバインドします。

<TabControl ItemsSource="{Binding Workspaces}"
        SelectedItem="{Binding SelectedTab, Mode=TwoWay}"
        Margin="3"
        DockPanel.Dock="Top">
  <TabControl.ItemTemplate>
       <DataTemplate>
          <Label Content="{Binding DisplayName}" />
       </DataTemplate>
  </TabControl.ItemTemplate>
</TabControl>

最後にSelectedTab、新しいタブを追加するたびにプロパティを更新する必要があります。AddProduct次のように変更します。

    public void AddProduct(object obj)
    {
        var workspace = new ProductViewModel();
        Workspaces.Add(workspace);
        SelectedTab = workspace;
    }
于 2013-10-26T08:52:51.527 に答える