【问题标题】:dynamically Adding buttons to a Tab Control context at runtime在运行时动态地将按钮添加到选项卡控件上下文
【发布时间】:2014-12-10 03:54:40
【问题描述】:

我在 MVVM 环境中,我正在尝试将内容添加到我的选项卡项。我的标签项是动态生成的,并且工作正常。为了简化这一点,我有一个字典,将字符串存储为键(选项卡项标题)和列表(当前按钮(我知道打破 mvvm,我想摆脱打破 mvvm 模式))。我希望将我的按钮放置在我的项目上下文中的相应网格行/列中。我查看了数据模板(我的字典键如何映射到我的选项卡项标题),但不确定如何从列表中提取按钮对象。绑定到值返回列表属性,而不是按钮属性。

我的第一个问题是如何在运行时将按钮放入存储在列表中的选项卡控件上下文中。 我的第二个问题是如何确定它应该进入哪个网格行/列。我想让它成为 true(er) MVVM 并使用数据模板触发器,但现在我设置了最小宽度/高度来存储网格它应该包含在行/列中。

这是我目前得到的:

<TabControl Margin="10,10,10,26" Grid.Column="0" ItemsSource="{Binding FUGU}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Key}" />
            </DataTemplate>
        </TabControl.ItemTemplate>

        <TabControl.ContentTemplate>
            <DataTemplate>

            </DataTemplate>
        </TabControl.ContentTemplate>
...
</TabControl>

C# 视图模型

public Dictionary<string, List<Button>> FUGU{ get; set; }
//inside constructor
foreach(var item in Items)
        {
            if (!Categories.Contains(item.Category))
            {
                Categories.Add(item.Category);
                List<Button> buttons = new List<Button>();
                int row = 0;
                int col = 0;
                foreach (var i in Items.FindAll(x => x.Category == item.Category))
                {
                    Button btn = new Button() { Content = i.Name, Tag = i.SKU, MinWidth=col, MinHeight=row };
                    buttons.Add(btn);
                    if(row==10)
                    {
                        row = 0;
                        col += 1;
                    }
                }
                FUGU.Add(item.Category, buttons);
            }

        }

编辑: 所以我做了一些更改并创建了一个对象并找到了 ItemsControl 类。这是我更新的代码:

<TabControl Margin="10,10,10,26" Grid.Column="0" ItemsSource="{Binding FUGU}" Background="#FFE5E5E5">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Key}" />
            </DataTemplate>
        </TabControl.ItemTemplate>

        <TabControl.ContentTemplate>
            <DataTemplate>


                <ItemsControl ItemsSource="{Binding Value}" >
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>

                            <Grid x:Name="grid">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>

                                <Grid.RowDefinitions>
                                    <RowDefinition />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                    <RowDefinition Height="0*" />
                                </Grid.RowDefinitions>
                                <Button Content="{Binding content}" Tag="{Binding tag}" Grid.Row="{Binding gridRow}" Grid.Column="{Binding gridCol}" Margin="5" FontSize="31"/>

                            </Grid>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>


            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>

C# 视图模型

foreach(var item in Items)
        {
            if (!Categories.Contains(item.Category))
            {
                Categories.Add(item.Category);


                List<POSButtonInfo> btnInfoLst = new List<POSButtonInfo>();
                int row = 0;
                int col = 0;
                foreach (var i in Items.FindAll(x => x.Category == item.Category))
                {
                    btnInfoLst.Add(new POSButtonInfo { content = i.Name, tag = i.SKU, gridCol = col, gridRow = row });


                    if(row==9)
                    {
                        row = 0;
                        col += 1;
                    }
                    else
                        row+=1;
                }
                FUGU.Add(item.Category, btnInfoLst);
            }

        }

我的按钮中的绑定来自我的自定义对象。这些绑定工作正常,但是,我得到了一些意想不到的行为,例如在我看来,按钮不尊重网格,我的意思是我有 10 个行定义并创建了 12 个测试对象以放入我的视图中。正如您在代码中看到的那样,当命中 9(第 10 个元素)时,它应该转到下一列并从 0 开始。相反,它转到下一列,但不会重置第 0 行。此外,按钮对象不占用整个列,在设计视图中查看时,仅显示网格的第一行,而不是整个网格的正常视图。我是数据模板的新手,所以我确定我做错了什么。任何指导将不胜感激。

【问题讨论】:

  • 你为什么不用 Dictionary> 而不是 Dictionary> ???
  • 如果我想走那条路,我可以做一个用户控制,但我想要一个更适合 MVVM 的解决方案
  • 您最终会得到一个包含 10 个项目的 tabitem,每个 item 有 10 个网格。那是你真正想要的吗?

标签: c# .net wpf mvvm mvvm-light


【解决方案1】:

我要做的是以下。在我的 mainviewmodel 中,我将使用我的 tabitemviewmodels 创建一个列表

public List<ITabItemViewmodel> MyTabContent {get;private set}

然后我会用我想在此选项卡中显示的视图模型填充此列表。

 MyTabContent.Add(new NameVm());
 MyTabContent.Add(new AdressVm());
 MyTabContent.Add(new OtherVm());

tabviewmodel 可能看起来像这样

 public class NameVm : ITabItemViewmodel
 {
    public string HeaderText {get;set;}

    public ICommand MyCommand {get;set;}

    //other properties and stuff
 }

如果我有这么好的 tabitemviewmodel,我可以简单地使用 DataTemplates 让 wpf 呈现我的视图

 <TabControl ItemsSource="{Binding MyTabContent}">
    <TabControl.ItemTemplate>
        <!-- this is the header template-->
        <DataTemplate>
            <TextBlock Text="{Binding HeaderText}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <ContentPresenter Content="{Binding}"/>
    </TabControl.ContentTemplate>
</TabControl>

您当然应该在资源中的任何地方为您的“TabItemViews”定义 DataTemplates

<DateTemplate DataType="{x:Type NameVm}">
 <view:MyViewForNameVm/>
<DataTemplate>

示例视图

 <UserControl x:class="view:MyViewForNameVm">
   <!-- here are all my Controls with bindings for my NameVm-->
   <Button Command="{Binding MyCommand}"/>
 </UserControl>

【讨论】:

  • 我想尽量避免在我的视图模型中有 UI 内容。我更新的代码(底部 2 个代码块)成功地将数据放入我的 tabitem 内容中,但它不尊重网格。
  • ??我的视图模型中没有任何 ui 内容。你为什么这么认为?
  • 你的权利,我看错了课程(需要睡觉)。这与我现在拥有的有什么不同?我有一个类可以获取我的按钮内容、网格行/列位置标签。我可以创建我需要的一切,我不想将网格和其他 UI 放在我的 VM 中,那么我如何让我的 XAML 尊重发送给它的信息?我有一个列表的 POSButtonInfo 类是我的对象,它保存 UI 数据信息以正确格式化它。按钮并没有像我预期的那样呈现。
  • 你真的应该阅读更多关于 mvvm 的博客。看看我的小样本。我的视图模型中没有任何 ui 代码(例如,您有 Button 类)此外,我在 XAML 中使用绑定创建所有视图(对于所有 TabItems)。 MyTabContent 属性中的视图模型绑定到 TabControl 并由 wpf 通过 DataTemplates 呈现。
  • 我同意你的观点,你的 VM 中没有任何 UI 类。据我了解,我已经在按照您的建议进行操作,但规模较小。我的问题是如何让我的 XAML 尊重我在更新中发布的班级中的网格位置数据。
猜你喜欢
  • 2011-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 2012-08-09
相关资源
最近更新 更多