将字符串用作Silverlight中的数据模板的数据模板时的事件处理程序

时间:2013-01-07 01:19:53

标签: c# silverlight xaml

我正在尝试使用字符串以编程方式为数据表单形成一些xaml。我可以让组合框出现。但是当我尝试使用指定" MouseLeftButtonUp"或者#34; Loaded"字符串中的事件处理程序;进入后,页面将变为白色(没有明显的错误)。请参阅下面的相关代码。

     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;

4 个答案:

答案 0 :(得分:1)

一种解决方案是处理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事件。

我必须承认我无法在ComboBox上触发MouseLeftButtonUp事件。我不确定为什么会发生这种情况,但它似乎是ComboBox的一个普遍问题,而不是由于你构建XAML的方式而发生的事情。然而,我能够为ComboBox的SelectionChanged事件获取一个事件处理程序。

我还尝试直接调用Dispatcher.BeginInvoke方法替换OnBeginEdit行,但我发现这种方法不起作用。事件没有正确连线;再一次,我不确定为什么。

答案 1 :(得分:1)

在XAML中连接的事件处理程序需要在连接到XAML文件的代码隐藏中声明。对于ResourceDictionary或从XamlReader.Load加载的任何内容,不能有任何代码隐藏,因此无法在XAML中设置事件处理程序。解决这个限制的最简单方法是不从字符串构建模板,只需在XAML文件的参考资料部分声明它,然后就可以这样做了:

Resources["MyTemplate"] as DataTemplate

获取模板并将其分配给您在此处执行的代码,或者仅在XAML中使用StaticResource。只要它保留在与此代码相连的同一个XAML文件中,您当前在其中的事件处理程序应该可以正常工作。还需要更改字符串的动态部分以使用Bindings。

如果您想坚持使用XamlReader方法,则需要解决2个问题。

  1. 在呈现的模板
  2. 中找到ComboBox实例
  3. 等待呈现模板以查找ComboBox
  4. 要查找ComboBox,您需要先在模板文本中为其指定一个x:Name属性(您只需替换当前存在的事件代码)。接下来,您需要能够按名称在可视树中找到项目。这非常简单,您可以找到example here来做到这一点。

    要在正确的时间调用此代码,您需要重写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");
    });
    

    在您的情况下,您的模板可能需要等待才能在呈现之前切换到编辑状态,在这种情况下,您需要暂停连接事件并在数据表上找到其他事件国家改变了。

答案 2 :(得分:0)

您可以使用交互性来绑定事件

,而不是尝试直接连接事件

e.g。

...
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.Interactivity.InvokeCommandAction的副本,但是为了将事件args传递给命令而扩展,你可能想要做同样的事情。

答案 3 :(得分:0)

XamlReader.Load不允许在其中附加eventHandlers。 所以使用这种技术动态地将eventHandlers附加到它。

1-编写没有eventHandlers的Xaml字符串-But写入这些控件的Name属性。

2-用XamlReader.Load(str);

加载字符串

3-然后从中加载DataTemplate的内容。使用Grid template = ((Grid)(dt.LoadContent()));

注意:此处GridDataTemplate中的父控件。

4-找到要附加事件处理程序的名称控件。 Button img = (Button)template.FindName("MyButtonInDataTemplate");

我希望它有所帮助。