在Silverlight中使用字符串作为数据模板时的事件处理程序
本文关键字:程序 事件处理 数据 Silverlight 字符串 | 更新日期: 2023-09-27 17:50:48
我正在尝试使用字符串以编程方式为数据形式形成一些xaml。我可以让组合框出现。但当我试图使用代码指定"MouseLeftButtonUp"或"加载"的事件处理程序在字符串;进入页面后,页面会变成白色(没有明显的错误)。请参阅下面的相关代码。
StringBuilder editTemplate = new StringBuilder("");
editTemplate.Append("<DataTemplate ");
editTemplate.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
editTemplate.Append("xmlns:toolkit='http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit' ");
editTemplate.Append("xmlns:navigation='clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation' ");
editTemplate.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >");
editTemplate.Append("<StackPanel>");
editTemplate.Append(@" <toolkit:DataField Label='" + GetFieldWithoutNumber(theInfo, theDataContext) + "'>");
/* Won't Work */ editTemplate.Append(@" <ComboBox MouseLeftButtonUp='ComboBox_MouseLeftButtonUp' />");
/* Will Work */ editTemplate.Append(@" <ComboBox />");
editTemplate.Append(@" </toolkit:DataField>");
editTemplate.Append("</StackPanel></DataTemplate>");
dynamicDataForm.EditTemplate = XamlReader.Load(editTemplate.ToString()) as DataTemplate;
在XAML中连接的事件处理程序需要在连接到XAML文件的后台代码中声明。在ResourceDictionary或从XamlReader加载的任何东西的情况下。加载时不能有任何代码滞后,因此不能在XAML中设置事件处理程序。绕过此限制的最简单方法是不使用字符串构建模板,而只是在XAML文件的参考资料部分声明它,然后可以这样做:
Resources["MyTemplate"] as DataTemplate
来获取模板并在代码中分配它,就像你在这里做的那样,或者只是在XAML中使用StaticResource。只要它保持在连接到此代码的相同XAML文件中,当前其中的事件处理程序应该可以正常工作。字符串的动态部分也需要更改以使用Bindings。
如果您想坚持使用XamlReader方法,那么有两个问题需要解决。
- 在渲染模板中找到ComboBox实例
- 等待模板渲染完成后寻找ComboBox
要找到ComboBox,您需要首先在模板文本中给它一个x:Name属性(您可以替换当前存在的事件代码)。接下来,您需要能够根据名称在可视化树中定位项目。这是相当简单的,你可以在这里找到一个例子。
要在正确的时间调用这段代码,你要么需要重写OnApplyTemplate,不幸的是,如果你在UserControl之类的东西中,这将不起作用,或者使用另一个技巧来阻止它运行,直到所有控件都呈现出来。下面是一个完整的例子,可以放在构造函数中,并使用上面链接的find方法:
DataTemplate template = Resources["MyTemplate"] as DataTemplate;
dynamicDataForm.ContentTemplate = template;
Dispatcher.BeginInvoke(() =>
{
ComboBox button = FindVisualChildByName<ComboBox>(this, "MyControl");
if (button != null)
button.MouseLeftButtonUp += (s, _) => MessageBox.Show("Click");
});
在您的情况下,看起来您的模板可能需要等待切换到编辑状态,然后才能呈现,在这种情况下,您需要推迟连接事件,并在您的数据表单上查找当该状态更改时发生的其他事件
一种解决方案是处理DataForm的BeginningEdit
事件,并使用它来订阅ComboBox的MouseLeftButtonUp
事件。
isEventWiredUp
的私有字段。我们将使用此字段来跟踪我们是否订阅了该事件,并防止该事件被多次订阅。
接下来,将x:Name="..."
属性添加到ComboBox
。我们使用这个名称来访问组合框。
完成后,添加以下两个方法,应该执行您想要的操作。将yourComboBoxName
替换为您给组合框的x:Name
:
private void dynamicDataForm_BeginningEdit(object sender, CancelEventArgs e)
{
Dispatcher.BeginInvoke(OnBeginEdit);
}
private void OnBeginEdit()
{
if (!isEventWiredUp)
{
var combobox = dynamicDataForm.FindNameInContent("yourComboBoxName") as ComboBox;
if (combobox != null)
{
combobox.MouseLeftButtonUp += combobox_MouseLeftButtonUp;
isEventWiredUp = true;
}
}
}
为DataForm的BeginningEdit
事件订阅这两个方法中的第一个。
我不得不承认我无法让MouseLeftButtonUp
事件在ComboBox上触发。我不确定为什么会发生这种情况,但这似乎是ComboBox的一般问题,而不是由于构造XAML的方式而发生的问题。但是,我能够为ComboBox的SelectionChanged
事件获得一个事件处理程序。
我还尝试用直接调用OnBeginEdit
方法来替换Dispatcher.BeginInvoke
行,但我发现这种方法不起作用。这些事件并没有正确地连接起来;我也不知道为什么。
您可以使用交互性来绑定事件,而不是尝试直接连接事件
。
...
editTemplate.Append("xmlns:i='clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity' ");
...
editTemplate.Append(@"
<ComboBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName='MouseLeftButtonUp'>
<i:InvokeCommandAction Command='{Binding DataContext.YourCommand,
RelativeSource={RelativeSource AncestorType=XXX}}'
CommandParameter='{Binding}'/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>");
,您可能必须使用一些祖先绑定来获得定义处理程序的上下文。我使用了InvokeCommandAction的自定义实现;基本上是system . windows . interactive . invokecommandaction的副本,但进行了扩展,以便将事件参数传递给命令,您可能也想这样做。
XamlReader。加载不允许在其中附加eventhandler。因此,使用这种技术来动态地将eventhandler附加到它上面。
1-编写不带eventhandler的Xaml字符串-但要编写这些控件的Name属性。
2-用XamlReader.Load(str);
3-然后加载DataTemplate的内容。using Grid template = ((Grid)(dt.LoadContent()));
注意:这里Grid
是DataTemplate
的父控件。
4-按名称找到要附加事件处理程序的控件。Button img = (Button)template.FindName("MyButtonInDataTemplate");