ItemsControl 非常常用和好用的控件,我经常将之用于配置界面!
比如这么一个配置界面:
整体是一个ItemsControl,每个子界面就是其中的一个Item。
ItemsControl 的 ItemsSource 绑定到 ParameterInfo 的集合
public ObservableCollection<ParameterInfo> configInfos { get; set; } = new ObservableCollection<ParameterInfo>();
每个Item 绑定的内容都对应集合元素的项 ParameterInfo 。
public class ParameterInfo : BindableBase
{
public const string file_name = "调试参数";
#region 模板匹配相关参数
public MatchInfo matchInfo { get; set; } = new MatchInfo();
private string mdPath;
/// <summary>
/// 模板路径
/// </summary>
public string MdPath
{
get { return mdPath; }
set { SetProperty(ref mdPath, value); }
}
#endregion
#region 瑕疵检测
public DefectInfo defectInfo { get; set; } = new DefectInfo();
#endregion
private string proName = "未命名";
/// <summary>
/// 项目名称
/// </summary>
public string ProName
{
get { return proName; }
set { SetProperty(ref proName, value); }
}
}
这里有个问题,每个子界面都有一个“打开” 按键。而 打开按键的命令绑定不在ParameterInfo 中,而是在ViewModel中,如果直接填写 命令名称,就会绑定失败。
于是就有写法:
<Button MinWidth="50" DockPanel.Dock="Right"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.OpenMdCmd}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}">打开</Button>
首先我们看到:
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.OpenMdCmd}"
就是解决在ItemsControl,无法找到数据源的问题,使用了 RelativeSource,通过 FindAncestor的方式,找到了 UserControl 的 DataContext 中的 命令属性定义。
我在之前的文章中也介绍到了:
【wpf】深度解析,Bingding是如何寻找数据源的_wpf findan_code bean的博客-CSDN博客目前我常用存放数据源的一般控件都有Resources和DataContext属性,列表控件会多一个ItemsSource。可以放多个资源,但是需要给每一个资源指定一个key。而和只能放一个对象(不需要指定key)https://blog.csdn.net/songhuangong123/article/details/126195727?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167765404916800213065489%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=167765404916800213065489&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-126195727-null-null.article_score_rank_blog&utm_term=TemplatedParent&spm=1018.2226.3001.4450#:~:text=%E3%80%90wpf%E3%80%91%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90%EF%BC%8CBingding%E6%98%AF%E5%A6%82%E4%BD%95%E5%AF%BB%E6%89%BE%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84可以具体看看
此时,OpenMdCmd确实已经绑定成功,但是有个问题,每个子界面的 “打开按钮” 都会调用这个命令,OpenMdCmd对应的方法,如何得知具体是哪个子界面的调用的呢?
这里,就进入今天的主题内容,
CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}"
我们这里的 CommandParameter,就是给CMD传递参数,而且也使用了 RelativeSource 的方式。
这里的 Mode 使用的 TemplatedParent。这种方式,之前的那篇文章也提到过,不过当时只知道会用于 “控件模板”, 想不到在这里,用到“数据模板” 也有它的作用。
于是 OpenMdCmd 里 就接收一下这个参数,看看是个啥?
名称 | 值 | 类型 | |
---|---|---|---|
◢ | item | {"子母勾"} | object {System.Windows.Controls.ContentPresenter} |
◢ Content | "子母勾" | object {VisualMatching.Models.ParameterInfo} | |
proName | "子母勾" | string | |
MdPath | null | string | |
ProName | "子母勾" | string | |
▶ PropertyChanged | {Method = | System.ComponentModel.PropertyChangedEventHandler | |
▶ defectInfo | VisualMatching.Models.DefectInfo | ||
▶ matchInfo | VisualMatching.Models.MatchInfo | ||
mdPath | null | string | |
▶ 静态成员 |
就是 System.Windows.Controls.ContentPresenter,这个就是数据模板对应的玩意儿。
关于 ContentPresenter 我的另一篇文章有详细讲解:
【wpf】子项容器模板 控件模板 数据模板 逻辑树 视觉树 之间的关系_wpf模板 树_code bean的博客-CSDN博客wpf中的那些模板之深度解析https://blog.csdn.net/songhuangong123/article/details/126071796#:~:text=%E3%80%90wpf%E3%80%91%E5%AD%90%E9%A1%B9%E5%AE%B9%E5%99%A8%E6%A8%A1%E6%9D%BF%20%E6%8E%A7%E4%BB%B6%E6%A8%A1%E6%9D%BF%20%E6%95%B0%E6%8D%AE%E6%A8%A1%E6%9D%BF%20%E9%80%BB%E8%BE%91%E6%A0%91%20%E8%A7%86%E8%A7%89%E6%A0%91%20%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB
继续往里面看,它其中的一个属性,Content,就是我们自定义的子项类 ParameterInfo!
也就是说Content就是你当前选择的子项Item对应的数据。那么在进入主题时,提出问题也就迎刃而解了!
最近,再通过 Path 属性 过滤一下,就能直接拿到 ParameterInfo 对象:
CommandParameter="{Binding Path=Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"