方法一:传参按钮控件自身绑定的ItemSource

用WAF框架实现MVVM,按钮的点击事件都要通过Command来传递到这个View对应的ViewModel上,再通过ViewModel传递到上层的Controller层,在Controller层通过DelegateCommand处理按钮真正的事件。有时候需要给该Command附加上一些参数(CommandParameter),但是默认CommandParameter只能传递一个参数。谷歌搜到的解决方法很复杂,于是想了个办法CommandParameter参数传递的是这个按钮控件自身绑定的ItemSource,然后通过从ItemSource身上的DataContext来拿到数据,再截取字符串分割得到想要的部分数据(或者强转为ItemSource对应的实体类)。

正常情况下,Button的绑定:

<Button Command="{Binding BtnCommand}" />

这个Command会沿着View –> ViewModle –> Controller层传递。

如果这个Button是ListBox的Item,这个ListBox的Item要使用数据模板,且ItemsSource绑定到了这组Button的数据源,是这样绑:

<ListBox x:Name="listBox" ItemsSource="{Binding DataList}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid">
<local:WaitingProgress/>
<Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.BtnCommand}"
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}}"> <!-- 传参是Button控件绑定的ItemsSource,即这里是DataList列表 -->
<Image Tag="{Binding id}" x:Name="img" Stretch="UniformToFill" Width="150" Height="150" webImg:ImageDecoder.Source="{Binding icon}">
</Image>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate> <ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Name="wrapPanel" HorizontalAlignment="Stretch" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

这个ItemSource绑定的DataList是ViewModle中的一个实例列表。ViewModel关键代码如下:

private ICommand refreshDesignCommand; // 向上传递这个Command:View-->ViewModel-->Controller
public ICommand RefreshDesignCommand
{
get { return refreshDesignCommand; }
set { SetProperty(ref refreshDesignCommand, value); }
} private ObservableCollection<GoodsJsonData> dataList = null;
public ObservableCollection<GoodsJsonData> DataList
{
get { return dataList; }
set { dataList = value; }
}

实体类:

public class GoodsJsonData
{
public string id { get; set; } // 还可用于图片被点击调时,标记出是哪个缩略图被点击
public string icon { get; set; } // 缩略图
public string image { get; set; } // 大图
public string model { get; set; } // 该商品对应的模型XML public override string ToString()
{
return "id = " + id + " , icon = " + icon + " , image = " + image + " , model = " + model;
}
}

Controller层的关键代码:

private readonly DelegateCommand refreshDesignCommand;  // 缩略图的点击回调

[ImportingConstructor]
public WebImageController()
{
this.refreshDesignCommand = new DelegateCommand(p => RefreshDesignCommand((Button)p));
} private void RefreshDesignCommand(Button btn)
{
// 方法一:将DataContext打印字符串,截取出目标数据
string dataContext = btn.DataContext.ToString();
System.Console.WriteLine(dataContext); // id = 000201 , icon = http://192.168.1.222/mjl/4-01.png , image = 2/造型/4-01.png , model = xml/qiang07.xml
// 截取字符串来获得目标数据。 // 方法二:将DataContext强转为ItemSource对应的实体类类型
GoodsJsonData data = (GoodsJsonData)btn.DataContext;
// do what you want !

坑点:

  • 如果这个DataList列表的内容需要同步刷新,则类型**必须是**ObservableCollection。否则就算控件与数据绑定成功,控件只在初始化时能够正确显示数据,之后数据发生改变时,控件不会自动刷新。
  • WPF可以传递控件自身绑定的ItemSource数据,通过ItemSource携带的DataContext内容,来代替CommandParameter多传参的蛋疼问题。

其他建议:

  • 想要在一个控件上传递多个参数,可以传递控件自身,用控件的Tag和Uid属性绑定上数据。

今天在StackOverflow看到一个关于解决Command和CommandParameter的工具:
http://xcommand.codeplex.com/
以后可能会用到,先Mark。之后抽空看看。


 

方法二:多路绑定MultiBinding结合转换器Converter的使用

该方法是网上搜到的主流方式。


方法三:其他Trick

思路:用其他控件的属性来记录数据。传参时传递按钮控件自身,再通过按钮控件的视觉树布局找到找到绑定了其他数据的控件。

XAML:

<Grid>
<Button Content="测试按钮"
Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.YourCommand}"
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}}">
</Button>
<!-- 用于给点击按钮时,传递多个参数 -->
<Grid x:Name="studentIdGrid" Tag="{Binding studentId}"/>
<Grid x:Name="studentNameGrid" Tag="{Binding studentName}"/>
<Grid x:Name="studentAgeGrid" Tag="{Binding studentAge}"/>
</Grid>

Controller:

// 按钮点击触发的事件
private void YourCommand(object p)
{
Button btn = (Button)p; // 传参传递的是控件自身
DependencyObject parent = VisualTreeHelper.GetParent(btn);
List<Grid> list = this.FindVisualChildren<Grid>(parent);
string studentId = list[].Tag.ToString();
string studentName = (int)(list[].Tag);
int studentAge = list[].Tag.ToString(); // do something...
} // 从视觉树找到目标控件的所有子控件
private List<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
List<T> list = new List<T>();
if (depObj != null)
{
for (int i = ; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
list.Add((T)child);
} List<T> childItems = FindVisualChildren<T>(child); // 递归
if (childItems != null && childItems.Count() > )
{
foreach (var item in childItems)
{
list.Add(item);
}
}
}
}
return list;
}

小结:

  • 按钮的CommandParameter绑定了自身,将自身作为点击后触发的回调函数的参数传入。再用该按钮控件去找到其他控件或UI元素。
  • 使用了按钮的兄弟节点Grid的Tag属性来绑定目标数据,选择用Grid是因为我们只想用它来传参,而不需要看到它。因此用其他UI元素的Tag属性来传参,再设置Visibility="Collapse"也是可行的。
  • 同样选择用兄弟节点也不是必须的。也可以是父节点或子节点,只要能通过视觉树VisualTreeHelper找到就行。

【WPF】CommandParameter解决多传参问题的更多相关文章

  1. 超全table功能Datatables使用的填坑之旅--2:post 动态传参: 解决: ajax 传参无值问题.

    官网解释与方法:1 当向服务器发出一个ajax请求,Datatables将会把服务器请求到的数据构造成一个数据对象. 2 实际上他是参考jQuery的ajax.data属性来的,他能添加额外的参数传给 ...

  2. 帆软用工具测试超链接打开弹窗(iframe嵌套),解决js传参带中文传递有乱码问题

    1.新建超链接 随意点击一个单元格右击,选择 超级链接 2.在弹出的窗口中选择JavaScript脚本 如图: 其中红框框出的是几个要点   ,左边的就不讲了,右上角的参数cc是设置了公式remote ...

  3. 解决JS传参中文乱码

    function PopupFK(cNum,type){ var url = "contract!Paying.action"; url = url + "?contra ...

  4. 关于url传参中文乱码问题

    之前都一直很不了解中文编码得问题,之前在做项目中没碰到那么头痛的问题.所以一直没有了解中文乱码的问题. 问题描述: 地址: http://localhost:8080/sun-government/c ...

  5. WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参

    原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataC ...

  6. 【WPF】wpf用MultiBinding解决Converter需要动态传参的问题,以Button为例

    原文:[WPF]wpf用MultiBinding解决Converter需要动态传参的问题,以Button为例       用Binding并通过Converter转换的时候,可能偶尔会遇到传参的问题, ...

  7. MvvmCross for WPF 支持子窗体显示、关闭、传参

    最近在做 PCL(Portable Class Library)平台的项目,所以发一下自己遇到的问题 MvvmCross 是 PCL 平台的一个 MVVM 框架 地址:https://github.c ...

  8. 使用call、apply和bind解决js中烦人的this,事件绑定时的this和传参问题

    1.什么是this 在JavaScript中this可以是全局对象.当前对象或者任意对象,这完全取决于函数的调用方式,this 绑定的对象即函数执行的上下文环境(context). 为了帮助理解,让我 ...

  9. url传参中文乱码解决

    url传参request.setCharacterEncoding("utf-8");无法解决中文乱码问题 解决方法: 修改tomcat---conf----server.xml文 ...

随机推荐

  1. 用css3做一个求婚小动画

    概述 本案例主要是运用到了css3的animation.keyframes.transform等属性,熟悉了,就可以做更多的其他动画效果,这几个属性功能非常强大. 详细 代码下载:http://www ...

  2. hihoCoder 1014 Trie树 (Trie)

    #1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描写叙述 小Hi和小Ho是一对好朋友.出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮 ...

  3. Java IO:BIO和NIO差别及各自应用场景

    转载请注明出处:jiq•钦's technical Blog - 季义钦 引言 BIO和NIO是两种不同的网络通信模型,现现在NIO已经大量应用在Jetty.ZooKeeper.Netty等开源框架中 ...

  4. 使用 Feed43

    1.打开 Feed43 2.将标题.链接,时间等变化的字段删去用 {%} 代替.将固定且多余的字段删去用 {*} 代替.注意,源码中有换行的地方均需要添加{*} . 3.活学活用

  5. nginx中的502错误

    遇到这种情况,首先看一下慢日志 [17-Aug-2015 13:13:43] WARNING: [pool www] child 27780, script '/data/s.com/index.ph ...

  6. xargs详解

    一.场景 这个命令是错误的 find ./ -perm +700 |ls -l 这样才是正确的 find ./ -perm +700 |xargs ls -l  二.用法 [root@localhos ...

  7. js replaceChild

    //父亲元素.replaceChild(新,旧) 1 <ul id="city"> <li id="bj">北京</li> ...

  8. 【LeetCode】49. Anagrams (2 solutions)

    Anagrams Given an array of strings, return all groups of strings that are anagrams. Note: All inputs ...

  9. Eclipse 去掉JavaScript Validator

    http://www.cnblogs.com/wucg/archive/2012/08/06/2625458.html eclipse有些时候,javascript文件总是通不过eclipse的编译校 ...

  10. Java虚拟机学习 - 查看JVM参数及值的命令行工具(6)

    查看JVM各个参数值方式 1. HotSpot vm中的各个globals.hpp文件  查看jvm初始的默认值及参数 globals.hpp globals_extension.hpp c1_glo ...