从外部视图模型访问选项卡数据

access tab data from outside view model

我的应用程序基本上是这样的,我使用的是 mvvm 模式,但我还是新手。在每个选项卡中,用户可以动态添加选项卡,如图所示。在每个选项卡中,都有文本框和复选框。

基本结构是 PriceViewModel.cs、PriceTab.xaml(用户控件)和 MainWindow.xaml。

在PriceViewModel.cs

public class PriceViewModel : PriceTabItem
{

    private string _PriceLevel;
    private bool _Buy;
    private bool _Sell;
    public string PriceLevel
    {
        get { return _PriceLevel; }
        set
        {
            _PriceLevel = value;
            OnPropertyChanged("PriceLevel");
        }
    }
    public bool Buy
    {
        get { return _Buy; }
        set
        {
            _Buy = value;
            OnPropertyChanged("Buy");
        }
    }
    public bool Sell
    {
        get { return _Sell; }
        set
        {
            _Sell = value;
            OnPropertyChanged("Sell");
        }
    }
    public PriceViewModel()
    {

    }

}

public abstract class PriceTabItem : PropertyChangedBase
{
    public string Title { get; set; }
    public string Header { get; set; }
    public string Content { get; set; }
}

public class PriceTabControl : PropertyChangedBase
{
    public ObservableCollection<PriceTabItem> Tabs { get; set; }
    private PriceTabItem _selectedTab;
    public PriceTabItem SelectedTab
    {
        get { return _selectedTab; }
        set
        {
            _selectedTab = value;
            OnPropertyChanged("SelectedTab");
        }
    }

    public Command AddNewTabCommand { get; set; }

    public PriceTabControl()
    {

        Tabs = new ObservableCollection<PriceTabItem>();
        AddNewTabCommand = new Command(AddNewTab);
    }
    private void AddNewTab()
    {
        var newtab = new PriceViewModel { Title = "Tab #" + (Tabs.Count + 1) };
        Tabs.Add(newtab);
        SelectedTab = newtab;
    }
}

在PriceTab.xaml中:

    <UserControl x:Class="MyApp.PriceTab"
         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" 
         xmlns:local="clr-namespace:MyApp.ViewModels"
         mc:Ignorable="d" 
        d:DesignHeight="300" d:DesignWidth="700">
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:PriceViewModel}">

<Grid>
    <TextBox HorizontalAlignment="Left" Height="19" Text="{Binding PriceLevel}" Margin="101,155,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="81" RenderTransformOrigin="-0.177,0.286"/>
    <CheckBox Content="Buy" IsChecked="{Binding Buy}" HorizontalAlignment="Left" Height="20" Margin="16,109,0,0" VerticalAlignment="Top" Width="73"/>
    <CheckBox Content="Sell" IsChecked="{Binding Sell}" HorizontalAlignment="Left" Height="20" Margin="122,109,0,0" VerticalAlignment="Top" Width="73"/>

</Grid>

</DataTemplate>
</UserControl.Resources>
<DockPanel>

    <Button Command="{Binding AddNewTabCommand}" Content="AddNewTab"
            DockPanel.Dock="Bottom"/>

    <TabControl ItemsSource="{Binding Tabs}"
                SelectedItem="{Binding SelectedTab}"
                DisplayMemberPath="Title">
    </TabControl>
</DockPanel></UserControl>

在PriceTab.xaml.cs:

public partial class HistogramPriceTab : UserControl
{
    public HistogramPriceTab()
    {
        InitializeComponent();
        DataContext = new PriceTabControl();
    }
}

在MainWindow.xaml中:

<Window x:Class="MyApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MyApp"
    mc:Ignorable="d"
    Title="MainWindow" Height="550" Width="850">

    <Grid Width="Auto" Height="Auto">
        <Button Name="SaveButton" Content="Save" HorizontalAlignment="Left" Height="33.16" Margin="701.5,11,0,0" VerticalAlignment="Top" Width="88.5" Click="SaveButton_Click"/>

        <TabControl HorizontalAlignment="Left" Height="485" Margin="-7,28,0,-7.6" VerticalAlignment="Top" Width="850" >
            <TabItem>
                <local:OtherTabs></local:OtherTabs>
            </TabItem>
            <TabItem Name="Price" Header="Price">
                <Grid Background="#FFE5E5E5">
                    <local:PriceTab></local:PriceTab>
                </Grid>
            </TabItem>
            <TabItem>
                <Grid Background="#FFE5E5E5">
                    <local:OtherTabs></local:OtherTabs>
                </Grid>
            </TabItem>
            <TabItem>
                <Grid Background="#FFE5E5E5">
                    <local:OtherTabs></local:OtherTabs>
                </Grid>
            </TabItem>
            <TabItem>
                <Grid Background="#FFE5E5E5">
                    <local:OtherTabs></local:OtherTabs>
                </Grid>
            </TabItem>
            <TabItem>
                <Grid Background="#FFE5E5E5">
                    <local:OtherTabs></local:OtherTabs>
                </Grid>
            </TabItem>
            <TabItem>
                <Grid Background="#FFE5E5E5">
                   <local:OtherTabs></local:OtherTabs>
                </Grid>
            </TabItem>
            <TabItem>
                <Grid Background="#FFE5E5E5">
                    <local:OtherTabs></local:OtherTabs>
                </Grid>
            </TabItem>

        </TabControl>
    </Grid></Window>

所以在右上角我有一个 "save" 按钮,当点击时,它必须从选项卡中获取所有输入并根据它们进行一些计算和图表显示到下一个window。所以基本上我希望下一个 window 能够引用来自这个 window 的所有输入。我如何使用模式来解决这个问题? 提前致谢!

硬写 xaml 不允许您动态创建标签。

您应该考虑使用 ItemControl 及其 itemSouce 绑定到 priceviewmodel 中的选项卡视图模型列表来创建选项卡。看看 this tutorial about itemcontrol

这样当你想做一些需要关于所有选项卡的信息的业务时,你可以通过 tabsviewmodels 列表访问它们

后来想通了,所以要引用选项卡和里面的所有项目, 请参阅下面的代码,我们可以使用 xaml 文件访问子项来访问价格水平(例如)文本框。

 var pricetabs = (((this.Price.Content as Grid).Children[0] as PriceTab).DataContext as ViewModels.PriceTabControl).Tabs;
 String res = "";
 foreach (ViewModels.PriceViewModel v in pricetabs)
 {
     res += v.PriceLevel.ToString()
 }

老实说,我不确定这是不是正确的方法,或者它是否破坏了 mvvm 结构,但它确实起作用了!