简体   繁体   中英

Caliburn.Micro & Telerik WPF Controls

Hope you're all well.

I am using Caliburn.Micro with Telerik's WPF controls to build a tabbed interface. Using RadTabControl I have the following code;

<telerik:RadTabControl x:Name="Items" Grid.Row="1" TabStripPlacement="Bottom">
    <telerik:RadTabControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Image Source="{Binding DisplayIcon}" Width="16" Height="16"/>
                <TextBlock Text="{Binding DisplayName}"/>
            </StackPanel>
        </DataTemplate>
    </telerik:RadTabControl.ItemTemplate>
</telerik:RadTabControl>

The tab has the correct header but the contents read ".../MyViewModel" (ellipses replace full path) instead of the Screen that should be displayed.

If I replace <telerik:RadTabControl... with <TabControl... this all works as intended.

What am I missing?

Caliburn's conventions system is only configured for WPF controls that are out-of-the-box. When it sees the RabTabControl, it doesn't recognize it, so it searched it's class hierarchy looking for something it does recognize. In this case, it probably matches on either Selector or ItemsControl. This is why there is a partial application of conventions. In order to get exactly what you want, you need to add a convention to the ConventionManager for RadTabControl that does exactly what you want. Here is how the TabControl convention is defined:

AddElementConvention<TabControl>(TabControl.ItemsSourceProperty, "ItemsSource", "SelectionChanged")
.ApplyBinding = (viewModelType, path, property, element, convention) => {
    if(!SetBinding(viewModelType, path, property, element, convention))
        return;

    var tabControl = (TabControl)element;
    if(tabControl.ContentTemplate == null && tabControl.ContentTemplateSelector == null && property.PropertyType.IsGenericType) {
        var itemType = property.PropertyType.GetGenericArguments().First();
        if(!itemType.IsValueType && !typeof(string).IsAssignableFrom(itemType))
            tabControl.ContentTemplate = DefaultItemTemplate;
    }

    ConfigureSelectedItem(element, Selector.SelectedItemProperty, viewModelType, path);

    if(string.IsNullOrEmpty(tabControl.DisplayMemberPath))
        ApplyHeaderTemplate(tabControl, TabControl.ItemTemplateProperty, viewModelType);
};

I think you should be able to take the code and with a few minor modifications, make it do what you want. Note that some of the methods called in the above code actually exist on the ConventionManager, so you will need to fix that up. You should add your convention in your Bootstrapper's Configure override. For an additional sample of this, have a look at the WP7 template's Bootstrapper, which defines custom conventions for Pivot and Panarama.

Caliburn.Micro.Telerik contains conventions for Telerik's WPF controls, as well as some other Telerik+WPF specific stuff like an IWindowManager implementation and two applications with examples.

You can check out the source code or the nuget package .

The convention for RadTabControl looks like this:

ConventionManager.AddElementConvention<RadTabControl>(RadTabControl.ItemsSourceProperty,
                                                  "ItemsSource",
                                                  "SelectionChanged")
.ApplyBinding = (viewModelType, path, property, element, convention) =>
{
    if (!ConventionManager.SetBindingWithoutBindingOrValueOverwrite(viewModelType,
                                                                    path,
                                                                    property,
                                                                    element,
                                                                    convention,
                                                                    RadTabControl.ItemsSourceProperty))
        return false;

    var tabControl = (RadTabControl) element;
    if (tabControl.ContentTemplate == null
        && tabControl.ContentTemplateSelector == null
        && property.PropertyType.IsGenericType)
    {
        var itemType = property.PropertyType.GetGenericArguments().First();
        if (!itemType.IsValueType && !typeof (string).IsAssignableFrom(itemType))
            tabControl.ContentTemplate = ConventionManager.DefaultItemTemplate;
    }
    ConventionManager.ConfigureSelectedItem(element,
                                            RadTabControl.SelectedItemProperty,
                                            viewModelType,
                                            path);

    if (string.IsNullOrEmpty(tabControl.DisplayMemberPath))
        ConventionManager.ApplyHeaderTemplate(tabControl,
                                              RadTabControl.ItemTemplateProperty,
                                              RadTabControl.ItemTemplateSelectorProperty,
                                              viewModelType);
    return true;
};

Hope this helps...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM