来自WPF用户控件库的UserControl绑定不能与ContentControl

时间:2017-08-25 13:58:00

标签: c# wpf mvvm user-controls caliburn.micro

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


初始

创建新的Wpf App v4.6.2

  • 安装Nuget Caliburn.Micro v3.1.0
  • 安装Nuget Caliburn.Micro.Start v3.1.0
  • 做出如http://caliburnmicro.com/documentation/nuget所述的改编
    • 改编app.xaml
    • 删除StartupUri
    • 添加ResourceDictionary
    • 检查AppBootstrapper
    • 删除MainWindow.xaml
  • 将按钮x:Name="DoIt"添加到ShellView.xaml
  • 使用MessageBox.Show()将public void DoIt()添加到ShellViewModel.cs
  • 测试此初始版本

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


UserControl View

  • 添加UserControl并为其命名,例如TestUcView
  • 添加Textbox并提供名称,例如UcValue
<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>


UserControl ViewModel

  • 添加具有相应名称TestUcViewModel
  • 的类
  • 将类更改为public并从屏幕派生并使用Caliburn.Micro
  • 添加
  • 将具有相应名称的媒体资源添加到TextBox,例如UcValue
public class Test1UcViewModel : Screen
{
    private string _UcValue;
    public string UcValue { get => _UcValue; set { _UcValue = value; NotifyOfPropertyChange(() => UcValue); } }

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


UserControl Integration

  • 在ShellViewModel中为ViewModel创建公共属性并在构造函数中创建实例
  • 在视图中创建控件以进行绑定

    1. 可能性:将ContentControl放在ShellView.xaml中,其名称与ViewModel属性相同(ViewModel优先)
    2. 可能性:编译并将UserControl放入ShellView.xaml并为此命名空间添加cal:Bind.Model="{Binding <ViewModel-Property-Name>}"

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


BUT,

...现在,通过集成属于WPF用户控件库(dll)的第三个UserControl,Caliburn绑定在使用时不会对来自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>

Cannot find UserControl

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

1 个答案:

答案 0 :(得分:2)

Caliburn.Micro使用简单的命名模式来查找它应绑定到视图模型并显示的UserControl,它只搜索您通过AssemblySource.Instance可以搜索的任何程序集:ViewLocator.LocateForModelType {3}}

您可以通过设置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; }; } 属性并实现自己的属性来覆盖此逻辑。以下基本示例应该为您提供这个想法:

    for item in medicineArray {
        let obj = item as NSDictionary

        if let dayInt = Int(obj["day"]){
            dateComp.day = dayInt
        }

        if let hourInt = Int(obj["time"]){
            dateComp.hour = hourInt
        }

    }