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 添加到 Workspaces Collection。

我已经定义了多个数据模板(每个 ViewModel 一个)。这是一个:

<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 然后回到原来的 oen,然后所有输入的信息都消失了(对象为空)。

  • 当我打开一个 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 回答