C# WPF从代码隐藏向现有样式添加触发器
我有一个C# WPF从代码隐藏向现有样式添加触发器,c#,wpf,C#,Wpf,我有一个TabControl,其中一些选项卡是用XAML声明的。我想添加新选项卡,并将其IsEnabled属性绑定到其内容的某些属性: for (int i = 0; i < context.Pictures.Count; ++i) { var tabItem = new TabItem(); var title = "Some title" tabItem.Header = title;
TabControl
,其中一些选项卡是用XAML声明的。我想添加新选项卡,并将其IsEnabled
属性绑定到其内容的某些属性:
for (int i = 0; i < context.Pictures.Count; ++i)
{
var tabItem = new TabItem();
var title = "Some title"
tabItem.Header = title;
var image = new Image();
Binding sourceBinding = new Binding(nameof(context.Pictures) + $"[{i}]");
sourceBinding.Source = context;
image.SetBinding(Image.SourceProperty, sourceBinding);
image.Width = 800;
image.Height = 600;
DataTrigger isEnabledTrigger = new DataTrigger() { Binding = sourceBinding, Value = null };
isEnabledTrigger.Setters.Add(new Setter(TabItem.IsEnabledProperty, false));
tabItem.Content = image;
tabControl.Items.Add(tabItem);
}
for(int i=0;i
如果内部图片为null
(应用isEnabledTrigger
),我想禁用选项卡。这里的问题是tabItem
的样式是从包含它的tabControl
派生出来的,所以我不能用触发器创建一个样式并将其应用于tabItem
。当然,我可以复制原始样式并硬编码,但我认为这不是解决问题的好方法
所以,要解决我的问题,我有两个想法:
是否有更合理的方法将
TabControl
sIsEnabled
绑定到包含的Image
s值?不要直接添加TabItem
。使用数据模型。这是所有项目控制的推荐方法。然后为数据模型定义一个DataTemplate
,并将其分配给TabControl.ContentTemplate
。
使用选项卡control.ItemTemplate
布局标题。为
选项卡control.ItemContainerStyle
定义样式
,可以非常轻松地设置所需的触发器。使用C#进行布局从来都不是一个好主意。始终使用XAML
见:
最小模型类应如下所示:
PictureModel.cs
// All binding source models must implement INotifyPropertyChanged
public class PictureModel : INotifyPropertyChanged
{
private string title;
public string Title
{
get => this.title;
set
{
this.title = value;
OnPropertyChanged();
}
}
private string source;
public string Source
{
get => this.source;
set
{
this.source = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<PictureModel> Pictures { get; }
private void CreateTabItems(Context context)
{
foreach (string imageSource in context.Pictures)
{
var pictureModel = new PictureModel()
{
Title = "Some Title",
Source = imageSource
};
this.Pictures.Add(pictureModel);
}
}
}
ViewModel.cs
// All binding source models must implement INotifyPropertyChanged
public class PictureModel : INotifyPropertyChanged
{
private string title;
public string Title
{
get => this.title;
set
{
this.title = value;
OnPropertyChanged();
}
}
private string source;
public string Source
{
get => this.source;
set
{
this.source = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<PictureModel> Pictures { get; }
private void CreateTabItems(Context context)
{
foreach (string imageSource in context.Pictures)
{
var pictureModel = new PictureModel()
{
Title = "Some Title",
Source = imageSource
};
this.Pictures.Add(pictureModel);
}
}
}
类视图模型:INotifyPropertyChanged
{
公共可观察收集图片{get;}
私有void CreateTabItems(上下文)
{
foreach(context.Pictures中的字符串imageSource)
{
var pictureModel=new pictureModel()
{
Title=“一些标题”,
源=图像源
};
this.Pictures.Add(pictureModel);
}
}
}
main window.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<!-- Layout the tab content -->
<TabControl ItemsSource="{Binding Pictures}">
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type viewModels:PictureModel}">
<Image Source="{Binding Source}" />
</DataTemplate>
</TabControl.ContentTemplate>
<!-- Layout the tab header -->
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type viewModels:PictureModel}">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</TabControl.ItemTemplate>
<!-- Setup triggers. The DataContext is the current data model -->
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Source}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Window>
您应该根据当前的
样式创建样式
:
Style style = new Style(typeof(TabItem))
{
BasedOn = FindResource(typeof(TabItem)) as Style
};
DataTrigger isEnabledTrigger = new DataTrigger() { Binding = sourceBinding, Value = null };
isEnabledTrigger.Setters.Add(new Setter(TabItem.IsEnabledProperty, false));
style.Triggers.Add(isEnabledTrigger);
tabItem.Style = style;
或
…取决于当前样式的应用方式
这就是使用DataTrigger
扩展现有样式的方法,这是解决此问题的好方法。正确的方法是为选项卡内容定义DataTemplate
,并将其分配给TabControl.ContentTemplate
。