将一个按钮绑定到每个在TabControl中的3个不同的DataGrid中

如何解决将一个按钮绑定到每个在TabControl中的3个不同的DataGrid中

我正在一个包含TabControl的项目中。 在我的视图模型中,每个TabItem中都有一个DataGrid绑定到一个ObservableCollection

我需要将 Edit Button绑定到当前聚焦的DataGridTabItem聚焦)上。 无需将多个“硬”编码为一个DataGrid / TabItem的按钮并使用MVVM模式,就可以轻松实现这一目标吗?

基本上是这样的顺序:TabControl->选定的TabItem-> DataGrid-> SelectedItem

Tabcontrol with Datagrids and Button

示例XAMLcode(基本的无格式等实际格式):

<Button Content="Edit"
        Command="{Binding ExecuteEditMessmittelCommand}"
        CommandParameter="{Binding ElementName=Messmittel_DataGrid,Path=SelectedItem}">
</Button>

<TabControl>

   <TabItem Header="Messmittel">
             <DataGrid x:Name="Messmittel_Datagrid"
                       ItemsSource="{Binding MessmittelDisplayCollection}">
                <DataGrid.Columns>
                   <DataGridTextColumn Header="ID"
                        Binding="{Binding Path=Benutzer_ID}"

                   <DataGridTextColumn Header="Seriennummer"
                        Binding="{Binding Path=Seriennummer}"

                   <DataGridTextColumn Header="MessmittelArt"
                        Binding="{Binding Path=Vorname}"
                </DataGrid.Columns>
             </DataGrid>
   </TabItem>

   <TabItem Header="Mechanik">
             <DataGrid x:Name="Mechanik_Datagrid"
                       ItemsSource="{Binding MechanikDisplayCollection}">
                //here is the datagrid content
             </DataGrid>
   </TabItem>

   <TabItem Header="Prüfhilfsmittel">
             <DataGrid x:Name="Pruefhilfsmittel_Datagrid"
                       ItemsSource="{Binding PruefhilfsmittelDisplayCollection}">
                //here is the datagrid content
             </DataGrid>
   </TabItem>

</TabControl>

视图模型(SetProperty仅触发INotifyPropertyChanged并设置值):

public ObservableCollection<MessmittelModel> MessmittelDisplayCollection
{
        get { return DatabaseDisplayModel.MessmittelCollection; }
        set { SetProperty(ref DatabaseDisplayModel.MessmittelCollection,value);}
}

public ObservableCollection<MessmittelModel> MechanikDisplayCollection
{
        get { return DatabaseDisplayModel.MechanischeMessmittelCollection; }
        set { SetProperty(ref DatabaseDisplayModel.MechanischeMessmittelCollection,value); }
}
public ObservableCollection<MessmittelModel> PruefhilfsmittelDisplayCollection
{
        get { return DatabaseDisplayModel.PruefhilfsmittelCollection; }
        set { SetProperty(ref DatabaseDisplayModel.PruefhilfsmittelCollection,value); }
}

在这种情况下,我认为我的视图模型不重要,但是如果您需要更多信息,请告诉我,我会提供。

解决方法

静态MVVM变体

我认为您必须分解主视图模型。您的主视图模型包含TabItems内的数据网格所绑定的列表。该视图模型很快就会膨胀,并且无法很好地分离视图和关注点。相反,您应该为包含TabControl的视图提供一个主视图模型,并为选项卡控件中的每个唯一视图提供一个单独的视图模型。

在您的示例中,一种视图模型类型就足够了,因为所有三个选项卡都包含相同的控件,并且仅在DataGrid中显示一个列表。此视图模型将公开由DataGrid和当前选择的属性绑定的集合。您可以通过多种方式分配集合,例如从外部进行设置通过主视图模型,将集合通过构造函数传递或为此传递服务。

public class MessmittelViewModel : BindableBase
{
   private MessmittelModel _selected;
   private ObservableCollection<MessmittelViewModel> _messmittelModels;

   // ...constructor,initialization of properties,other properties.

   public MessmittelModel Selected
   {
      get => _selected;
      set => SetProperty(ref _selected,value);
   }

   public ObservableCollection<MessmittelModel> MessmittelDisplayCollection
   {
      get => _messmittelModels;
      set { SetProperty(ref _messmittelModels,value);
   }
}

在主视图模型中,可以为每个选项卡公开一个视图模型属性。

public class MainViewModel: BindableBase
{
   private MessmittelViewModel _selectedViewModel;
   private MechanischeMessmittel _mechanischeMessmittelViewModel;

   // ...contructor,initialize properties,other code.

   public MessmittelViewModel SelectedViewModel
   {
      get => _selectedViewModel;
      set => SetProperty(ref _selectedViewModel,value);
   }

   public MechanischeMessmittelViewModel
   {
      get => _mechanischeMessmittelViewModel;
      private set => SetProperty(ref _mechanischeMessmittelViewModel,value);
   }
}

然后在您的XAML中将SelectedItem的{​​{1}}和标签的TabControl绑定。

DataContext

现在您可以将命令参数绑定到<TabControl SelectedItem="{Binding SelectedViewModel}"> <!-- ...other content. --> <TabItem Header="Mechanik" DataContext={Binding MechanischeMessmittelViewModel}"> <DataGrid ItemsSource="{Binding MessmittelDisplayCollection}"> <!-- ...data grid content. --> </DataGrid> </TabItem> </TabControl> 属性...

Selected

...或访问<Button Content="Edit" Command="{Binding ExecuteEditMessmittelCommand}" CommandParameter="{Binding SelectedViewModel.Selected}"/> 中的选定视图模型并获取其MainViewModel列表项。

Selected

动态MVVM变体

当您考虑创建可能包含不同视图的其他选项卡时,公开三个静态属性不是很可扩展,因此我向您展示如何以更动态的方式进行操作。假设您已经如上所述创建了var parameter = SelectedViewModel.Selected; 和一个MessmittelViewModel。创建基本类型的FoobarMessmittelViewModel,例如ObservableCollection和以前选择的属性。

MessmittelViewModelBase

public class MainViewModel: BindableBase { private MessmittelViewModelBase _selectedViewModel; private ObservableCollection<MessmittelViewModelBase> _messmittelModels; public MainViewModel() { // ...other code. MessmittelViewModels = new ObservableCollection<MessmittelViewModelBase>(); MessmittelViewModels.Add(new MessmittelViewModel(DatabaseDisplayModel.MessmittelCollection)); // ...add view models for the other tabs. } // ...other code. public MessmittelViewModelBase SelectedViewModel { get => _selectedViewModel; set => SetProperty(ref _selectedViewModel,value); } public ObservableCollection<MessmittelViewModelBase> MessmittelViewModels { get => _messmittelModels; set { SetProperty(ref _messmittelModels,value); } } 绑定到ItemsSource集合,并创建一个MessmittelViewModels来代表每种具体视图模型类型的视图。

DataTemplate

就是这样,<TabControl ItemsSource="{Binding MessmittelViewModels}"> <TabControl.Resources> <DataTemplate DataType="{x:Type MessmittelViewModel}"> <DataGrid ItemsSource="{Binding MessmittelDisplayCollection}"> <DataGrid.Columns> <DataGridTextColumn Header="ID" Binding="{Binding Path=Benutzer_ID}" <DataGridTextColumn Header="Seriennummer" Binding="{Binding Path=Seriennummer}" <DataGridTextColumn Header="MessmittelArt" Binding="{Binding Path=Vorname}" </DataGrid.Columns> </DataGrid> </DataTemplate> <!-- ...other data templates --> </TabControl.Resources> </TabControl> 现在将根据视图模型集合中的每个项目的类型为其创建一个适当的视图。由于现在存在不同的类型,因此您可以通过检查类型来选择代码中命令的参数(甚至可能为此选项卡启用了参数)。

TabControl

使用转换器的MVVM变体

对于您当前的方法,您还可以使用多值转换器仅在XAML中解决该问题。但是,这也是一个静态变体。该转换器将基于选项卡控件中的选定索引返回一个绑定值。

if (SelectedViewModel is MessmittelViewModel messmittelViewModel)
{
   var parameter = messmittelViewModel.Selected;
}

在XAML中,您必须像这样绑定public class SelectedIndexBindingConverter : IMultiValueConverter { public object Convert(object[] values,Type targetType,object parameter,CultureInfo culture) { return values[(int)values[0] + 1]; } public object[] ConvertBack(object value,Type[] targetTypes,CultureInfo culture) { throw new InvalidOperationException(); } }

CommandParameter

您还可以创建一个转换器以遍历可视化树并获取相应<Window.Resources> <local:SelectedIndexBindingConverter x:Key="SelectedIndexBindingConverter"/> </Window.Resources> <Button Content="Edit" Command="{Binding CommandTest}"> <Button.CommandParameter> <MultiBinding Converter="{StaticResource SelectedIndexBindingConverter}"> <Binding Path="SelectedIndex" ElementName="MyTabControl"/> <Binding Path="SelectedItem" ElementName="Messmittel_Datagrid"/> <Binding Path="SelectedItem" ElementName="Mechanik_Datagrid"/> <Binding Path="SelectedItem" ElementName="Pruefhilfsmittel_Datagrid"/> </MultiBinding> </Button.CommandParameter> </Button> <TabControl x:Name="MyTabControl"> <!-- ...tab items as before. --> </TabControl> 的选定项目,而无需绑定它,但这将假定为可视化结构,并且此解决方案更加健壮,因为您指定了元素明确。实际上,此转换器更灵活,因为它允许您将命令参数绑定到选项卡项中具有任何属性的任何控件。

请注意,您也可以通过触发器在XAML中实现相同的功能,但是我认为这会对控件的样式产生太多干扰,并且可能更难以重用。

,

执行此操作的多种方法是一种简便快捷的方法

“切换”选项卡处于选中状态

Button_OnButtonClicked(//eventargs){
   DataGrid dgridToEdit = null;
   if(TabControl.SelectedTabIndex == 0){
      dgridToEdit = firstDGrid;
   }
   else if(TabControl.SelectedTabIndex == 1){
      dgridToEdit = secondDGrid;
   }
   else if(TabControl.SelectedTabIndex == 2){
      dgridToEdit = thirdDGrid;
   }


   //... then do your things with the dGrid
   }

执行此操作的其他方法是onTabChanged事件,然后在新选项卡上引用DataGrid或为您提供当前关注的DataGrid的方法(如我的示例),依此类推。我希望我能帮助你..祝你好运!

,

针对此问题的一种可能的MVVM友好解决方案是使用TabItems的IsSelected属性:

<!-- language: lang-xml -->
<Button Content="Edit"
        Command="{Binding ExecuteEditCommand}">
</Button>

<TabControl>

   <TabItem Header="Messmittel"
            IsSelected={Binding IsMessmittelSelected}>
             <DataGrid x:Name="Messmittel_Datagrid"
                       ItemsSource="{Binding MessmittelDisplayCollection}">
                <DataGrid.Columns>
                   <DataGridTextColumn Header="ID"
                        Binding="{Binding Path=Benutzer_ID}"

                   <DataGridTextColumn Header="Seriennummer"
                        Binding="{Binding Path=Seriennummer}"

                   <DataGridTextColumn Header="MessmittelArt"
                        Binding="{Binding Path=Vorname}"
                </DataGrid.Columns>
             </DataGrid>
   </TabItem>

   <TabItem Header="Mechanik"
            IsSelected={Binding IsMechanikSelected}>
             <DataGrid x:Name="Mechanik_Datagrid"
                       ItemsSource="{Binding MechanikDisplayCollection}">
                //here is the datagrid content
             </DataGrid>
   </TabItem>

   <TabItem Header="Prüfhilfsmittel"
            IsSelected={Binding IsPrüfhilfsmittelSelected}>
             <DataGrid x:Name="Pruefhilfsmittel_Datagrid"
                       ItemsSource="{Binding PruefhilfsmittelDisplayCollection}">
                //here is the datagrid content
             </DataGrid>
   </TabItem>

</TabControl>
// DataContext above control is bound to:
// This method would be used by ExecuteEditCommand
private void OnExecuteEdit()
{
    if (IsMessmittelSelected)
    {
        // IsMessmittelSelected logic
    }
    else if (IsMechanikSelected)
    {
        // IsMechanikSelected logic
    }
    else if (IsPrüfhilfsmittelSelected)
    {
        // IsPrüfhilfsmittelSelected logic
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-