WPF 用户控件库中的 UserControl 绑定不适用于 ContentControl

UserControl binding from WPF User Control Library doesn't work with ContentControl

为什么绑定到 WPF 用户控件库的 Caliburn.Micro UserControl 不能与 ContentControl 一起使用?


初始

创建新的 Wpf App v4.6.2

✓ 检查!这运行并绑定工作...


用户控件视图

<UserControl x:Class="WpfApp1.Test2UcView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp1"
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="200" Visibility="{Binding UcVisibility}">
    <Grid >
        <TextBox x:Name="UcValue" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="100"/>
        <Button x:Name="UcAction" Content="Do specific" HorizontalAlignment="Left" Margin="120,10,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</UserControl>


用户控件视图模型

public class Test1UcViewModel : Screen
{
    private string _UcValue;
    public string UcValue { get => _UcValue; set { _UcValue = value; NotifyOfPropertyChange(() => UcValue); } }

    public void TestBut2() {
        MessageBox.Show("TestBut2");
    }
}


用户控件集成

✓ 检查!这将运行并绑定 UserControl 工作...


但是,

...现在集成属于 WPF 用户控件库 (dll) 的第三个 UserControl,当使用ContentControl 的语法。

public class ShellViewModel : Caliburn.Micro.PropertyChangedBase, IShell
{
    private Test1UcViewModel _Test1UserControlModel;
    private Test2UcViewModel _Test2UserControlModel;
    private Test3UcViewModel _Test3UserControlModel;

    public Test1UcViewModel Test1 { get => _Test1UserControlModel; set { _Test1UserControlModel = value; NotifyOfPropertyChange(() => Test1); } }
    public Test2UcViewModel Test2 { get => _Test2UserControlModel; set { _Test2UserControlModel = value; NotifyOfPropertyChange(() => Test2); } }
    public Test3UcViewModel Test3 { get => _Test3UserControlModel; set { _Test3UserControlModel = value;NotifyOfPropertyChange(() => Test3); } }

    public ShellViewModel()
    {
        _Test1UserControlModel = new Test1UcViewModel();
        Test1.UcValue = "Bubble";
        _Test2UserControlModel = new Test2UcViewModel();
        Test2.UcValue = "Simmer";
        _Test3UserControlModel = new Test3UcViewModel();
        Test3.Uc3Value = "Knocking on heavens door";
        Test1.UcVisibility = Visibility.Visible;
        Test2.UcVisibility = Visibility.Hidden;
        Test3.UcVisibility = Visibility.Hidden;
    }
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:cal="http://www.caliburnproject.org"
        xmlns:local="clr-namespace:WpfApp1" 
        xmlns:TestUcLib="clr-namespace:TestUcLib;assembly=TestUcLib" 
        x:Class="WpfApp1.ShellView" Width="500" Height="300">

    <Grid Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <TextBlock Text="Input"
                   TextWrapping="Wrap"
                   VerticalAlignment="Bottom"
                   HorizontalAlignment="Center"
                   FontSize="20" />
        <StackPanel>
            <Button x:Name="DoIt1" Content="Do it 1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="5"/>
            <Button x:Name="DoIt2" Content="Do it 2" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="5"/>
            <Button x:Name="DoIt3" Content="Do it 3" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="5"/>
        </StackPanel>

        <ContentControl x:Name="Test1" Grid.Column="1"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
        <ContentControl x:Name="Test2" Grid.Column="1"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
        <ContentControl x:Name="Test3" Grid.Column="1"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
        <!--This one works-->
        <!--<TestUcLib:Test3UcView cal:Bind.Model="{Binding Test3}" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>-->
    </Grid>

</Window>

当 UserControl 在 dll 中时,是否必须使用 <TestUcLib:Test3UcView cal:Bind.Model="{Binding Test3}" 而不是使用 ContentControl?

Caliburn.Micro 使用一个简单的命名模式来查找它应该绑定到视图模型并显示的 UserControl,它只搜索您通过 AssemblySource.Instance 公开为可搜索的任何程序集: http://caliburnmicro.com/documentation/conventions.

您可以通过设置 ViewLocator.LocateForModelType 属性 并实现您自己的逻辑来覆盖此逻辑。下面的基本示例应该会给您思路:

public class HelloBootstrapper : BootstrapperBase
{
    public HelloBootstrapper()
    {
        Initialize();
    }

    ...

    static Func<Type, DependencyObject, object, UIElement> _func;
    protected override void Configure()
    {
        var assembly = System.Reflection.Assembly.Load("WpfCustomControlLibrary1"); //<-- this is your assembly
        AssemblySource.Instance.Add(assembly);

        _func = ViewLocator.LocateForModelType;
        ViewLocator.LocateForModelType = LocateForModelType;
        ...
    }

    private static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) => {

        //use the default method first:
        UIElement view = _func(modelType, displayLocation, context);
        if (!(view is TextBlock))
            return view;

        var viewTypeName = modelType.Name.Replace("Model", string.Empty);
        var viewType = (from assmebly in AssemblySource.Instance
                        from type in assmebly.GetExportedTypes()
                        where type.Name == viewTypeName
                        select type).FirstOrDefault();

        return viewType == null ? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
            : Activator.CreateInstance(viewType) as UIElement;
    };
}