如何解决将一个按钮绑定到每个在TabControl中的3个不同的DataGrid中
我正在一个包含TabControl
的项目中。
在我的视图模型中,每个TabItem
中都有一个DataGrid
绑定到一个ObservableCollection
。
我需要将 Edit Button
绑定到当前聚焦的DataGrid
(TabItem
聚焦)上。
无需将多个“硬”编码为一个DataGrid
/ TabItem
的按钮并使用MVVM模式,就可以轻松实现这一目标吗?
基本上是这样的顺序:TabControl
->选定的TabItem
-> DataGrid
-> SelectedItem
示例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 举报,一经查实,本站将立刻删除。