C# 在Silverlight中将字符串用作dataform的数据模板时的事件处理程序
我试图使用字符串以编程方式为数据表单形成一些xaml。我可以让组合框出现。但是当我试图使用指定字符串中“MouseLeftButtonUp”或“Loaded”事件处理程序的代码时;进入页面后,页面将变为白色(无明显错误)。请参阅下面的相关代码C# 在Silverlight中将字符串用作dataform的数据模板时的事件处理程序,c#,silverlight,xaml,C#,Silverlight,Xaml,我试图使用字符串以编程方式为数据表单形成一些xaml。我可以让组合框出现。但是当我试图使用指定字符串中“MouseLeftButtonUp”或“Loaded”事件处理程序的代码时;进入页面后,页面将变为白色(无明显错误)。请参阅下面的相关代码 StringBuilder editTemplate = new StringBuilder(""); editTemplate.Append("<DataTemplate "); editTemplate.Append
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;
StringBuilder编辑模板=新的StringBuilder(“”);
editTemplate.Append(“”);
editTemplate.Append(“”);
editTemplate.Append(@“”);
/*无法工作*/editTemplate.Append(@“”);
/*将起作用*/editTemplate.Append(@“”);
editTemplate.Append(@“”);
editTemplate.Append(“”);
dynamicDataForm.EditTemplate=XamlReader.Load(EditTemplate.ToString())作为DataTemplate;
一种解决方案是处理数据表单的BeginingEdit
事件,并使用该事件将事件处理程序订阅到组合框的MouseLeftButtonUp
事件
为此,将名为isEventWiredUp
的私有字段添加到代码后面。我们将使用此字段跟踪是否已订阅该活动,并防止该活动被订阅多次
接下来,将x:Name=“…”
属性添加到您的组合框中。我们使用此名称来访问组合框
完成后,添加以下两种方法,这两种方法可以满足您的需要。将yourcomboxname
替换为您提供给组合框的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;
}
}
}
将这两个方法中的第一个订阅到数据表单的beginingedit
事件
我必须承认,我无法在组合框上触发MouseLeftButtonUp
事件。我不知道为什么会发生这种情况,但这似乎是ComboBox的一个普遍问题,而不是因为构建XAML的方式而发生的问题。但是,我能够为组合框的SelectionChanged
事件找到一个事件处理程序
我还尝试用直接调用OnBeginEdit
方法替换Dispatcher.BeginInvoke
行,但我发现这种方法不起作用。这些事件没有完全正确地联系起来;同样,我也不知道为什么。连接到XAML文件的代码隐藏中需要声明XAML中的事件处理程序。对于ResourceDictionary或从XamlReader.Load加载的任何内容,不能有任何代码隐藏,因此不能在XAML中设置事件处理程序。绕过此限制的最简单方法是,不要从字符串构建模板,只需在XAML文件的参考资料部分声明模板,然后您可以执行以下操作:
Resources[“MyTemplate”]作为数据模板
获取模板并像您在这里所做的那样在代码中分配它,或者只使用XAML中的StaticResource。只要它保持在与此代码连接的同一个XAML文件中,您当前拥有的事件处理程序就可以正常工作。字符串的动态部分也需要更改以使用绑定
如果您想坚持使用XamlReader方法,您有两个问题需要解决
在渲染模板中找到ComboBox实例
等待模板呈现后再查找组合框
要查找组合框,首先需要在模板文本中为其指定一个x:Name属性(您可以替换当前的事件代码)。接下来,您需要能够通过名称在可视化树中定位项目。这相当简单,您可以找到一个方法来实现这一点
要在正确的时间调用此代码,您要么需要重写OnApplyTemplate,不幸的是,如果您使用的是UserControl之类的控件,那么OnApplyTemplate将无法工作,要么使用另一个技巧在呈现所有控件之前阻止其运行。下面是一个完整的示例,可以在构造函数中使用上面链接的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");
});
DataTemplate=Resources[“MyTemplate”]作为DataTemplate;
dynamicDataForm.ContentTemplate=模板;
Dispatcher.BeginInvoke(()=>
{
ComboBox button=FindVisualChildByName(这是“MyControl”);
如果(按钮!=null)
button.MouseLeftButtonUp+=(s,)=>MessageBox.Show(“单击”);
});
在您的情况下,您的模板可能需要等待切换到编辑状态,然后才能呈现。在这种情况下,您需要暂停连接事件,并在数据表单上查找该状态更改时发生的其他事件。而不是尝试直接连接事件,您可以使用交互性绑定事件
e、 g
。。。
editTemplate.Append(“xmlns:i='clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity'”);
...
editTemplate.Append(@)
");
您可能需要使用一些祖先绑定来访问定义处理程序的上下文。我使用InvokeCommandAction的自定义实现;基本上是System.Windows.Interactivity.InvokeCommandAction的副本,但为了将事件参数传递给命令而进行了扩展,您可能需要执行相同的操作。XamlReader.Load不允许在其中附加事件处理程序。
因此,请使用此技术将EventHandler动态附加到它
1-在不使用EventHandler的情况下编写Xaml字符串-但要编写这些控件的Name属性
2-使用XamlReader.Load(str)加载字符串代码>
3-然后从中加载DataTemplate的内容。使用Grid模板=((Grid)(dt.LoadContent())代码>
注意:Grid
是DataTemplate
中的父控件
4-按要附加事件处理程序的名称查找控件。
Button img=(Button)template.FindName(“MyButtonInDataTemplate”)代码>
我希望它能有所帮助。这并不让我感到惊讶,您应该做的是在创建da后以编程方式连接事件处理程序
...
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>");