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
- 安装 Nuget Caliburn.Micro v3.1.0
- 安装 Nuget Caliburn.Micro.启动 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
并命名,例如TestUcView
- 添加一个
Textbox
并给出一个名字,例如Uc值
<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>
用户控件视图模型
- 添加class对应名称TestUcViewModel
- 将 class 更改为 public 并从屏幕派生并使用 Caliburn.Micro
添加
- 将具有相应名称的属性添加到
TextBox
,例如Uc值
public class Test1UcViewModel : Screen
{
private string _UcValue;
public string UcValue { get => _UcValue; set { _UcValue = value; NotifyOfPropertyChange(() => UcValue); } }
public void TestBut2() {
MessageBox.Show("TestBut2");
}
}
用户控件集成
- 在 ShellViewModel 中为 ViewModel 创建 public 属性 并在构造函数中创建一个实例
在要绑定的视图中创建控件
- 可能性:将
ContentControl
放入与 ViewModel 属性 同名的 ShellView.xaml
中(首先是 ViewModel)
- 可能性:编译
UserControl
并将其放入 ShellView.xaml
并为此添加 cal:Bind.Model="{Binding <ViewModel-Property-Name>}"
命名空间
✓ 检查!这将运行并绑定 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;
};
}
为什么绑定到 WPF 用户控件库的 Caliburn.Micro UserControl
不能与 ContentControl
一起使用?
初始
创建新的 Wpf App v4.6.2
- 安装 Nuget Caliburn.Micro v3.1.0
- 安装 Nuget Caliburn.Micro.启动 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
并命名,例如TestUcView - 添加一个
Textbox
并给出一个名字,例如Uc值
<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>
用户控件视图模型
- 添加class对应名称TestUcViewModel
- 将 class 更改为 public 并从屏幕派生并使用 Caliburn.Micro 添加
- 将具有相应名称的属性添加到
TextBox
,例如Uc值
public class Test1UcViewModel : Screen
{
private string _UcValue;
public string UcValue { get => _UcValue; set { _UcValue = value; NotifyOfPropertyChange(() => UcValue); } }
public void TestBut2() {
MessageBox.Show("TestBut2");
}
}
用户控件集成
- 在 ShellViewModel 中为 ViewModel 创建 public 属性 并在构造函数中创建一个实例
在要绑定的视图中创建控件
- 可能性:将
ContentControl
放入与 ViewModel 属性 同名的ShellView.xaml
中(首先是 ViewModel) - 可能性:编译
UserControl
并将其放入ShellView.xaml
并为此添加cal:Bind.Model="{Binding <ViewModel-Property-Name>}"
命名空间
- 可能性:将
✓ 检查!这将运行并绑定 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;
};
}