I am attempting to form some xaml for a dataform programmatically using a string. I can get the combo box to appear. but when I attempt to use the code specifying the “MouseLeftButtonUp” or the “Loaded” event handler in the string; the page will turn white (no noticeable error) out after going into it. Please see relevant code below.
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;
Event handlers hooked up in XAML are required to be declared in the code-behind connected to the XAML file. In the case of a ResourceDictionary or anything loaded from XamlReader.Load there can’t be any code-behind, so event handlers can’t be set in the XAML. The easiest way to get around this restriction would be to not build your template from strings and just declare it in the Resources section of your XAML file which you can then do like:
Resources["MyTemplate"] as DataTemplateto get the template and assign it in code like you’re doing here, or just use StaticResource in XAML. As long as it stays in the same XAML file connected to this code the event handlers you have in it currently should work fine. The dynamic part of the strings would also need to be changed to use Bindings.
If you want to stick with the XamlReader method you have 2 problems to solve.
To find the ComboBox you need to first give it an x:Name attribute in the template text (you can just replace the event code currently there). Next you need to be able to locate an item in the visual tree by name. This is fairly straightforward and you can find an example here to do that.
To call this code at the right time you either need to override OnApplyTemplate, which unfortunately won’t work if you’re in something like a UserControl, or use another trick to keep it from running until all the controls are rendered. Here’s a full example that could go in a constructor and uses the find method linked from above:
In your case it looks like your template might need to wait to switch to an edit state before it renders in which case you’d need to hold off on connecting the event and find some other event on your dataform that happens when that state is changed.