我在XAML用户控件(名为Block
)上具有DependecyProperty(名为BlockPresenter
),它期望数据类型为IBlock
。除其他事项外,此IBlock
接口具有Visual GetControl()
方法,该方法返回某种类型的元素,以允许用户编辑该特定块的值。 BlockPresenter
提供了一种选择要使用的块(例如BlockA,BlockB等)的方式,还显示了GetControl
返回的块本身值。
有些模型包含一个或多个IBlock
属性,它们的名称不同。这些模型中的每一个都有自己的用户控件,该控件具有与DataContext一样的模型。在用于模型控件的XAML中,我使用诸如<controls:BlockPresenter Block="{Binding Foo}" />
之类的行来显示控件,并允许用户更改其所选块的块类型或属性。
当用户从BlockPresenter中的下拉列表更改块类型时,将创建所选块的新实例并将其设置为Block DependencyProperty,演示者将为新块调用GetControl
。很好,但是问题在于这不会将新值发送给模型。
BlockPresenter.xaml
<Border BorderThickness="2" BorderBrush="#F00">
<StackPanel>
<ComboBox x:Name="BlockSelection" SelectedValuePath="BlockType" DisplayMemberPath="Name" SelectionChanged="BlockSelection_SelectionChanged" />
<ContentControl x:Name="ContentContainer" Margin="0" />
</StackPanel>
</Border>
BlockPresenter.xaml.cs
public BlockPresenter() {
InitializeComponent();
BlockSelection.ItemsSource = new List<BlockListItem> {
new BlockListItem("BlockA", typeof(BlockA)),
new BlockListItem("BlockB", typeof(BlockB)),
// BlockListItem is a simple class containing just "Name" and "BlockType" as read-only auto properties.
};
}
private static void OnBlockChange(DependencyObject conditionPresenter, DependencyPropertyChangedEventArgs eventArgs) {
var control = (BlockPresenter)conditionPresenter;
var newBlock = (IBlock)eventArgs.NewValue;
control.ContentContainer.Content = newBlock?.GetControl();
control.BlockSelection.SelectedValue = eventArgs.NewValue?.GetType();
}
public static readonly DependencyProperty BlockProperty = DependencyProperty.Register("Block", typeof(IBlock), typeof(BlockPresenter), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, OnBlockChange));
public IBlock Block {
get => (IBlock)GetValue(BlockProperty);
set => SetValue(BlockProperty, value);
}
private void BlockSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) {
Block = (IBlock)Activator.CreateInstance(BlockSelection.SelectedValue);
}
DefaultModelControl.xaml
<Grid>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefitions>
<Label Content="Main Block:" Grid.Row="0" />
<logic:BlockPresenter Block="{Binding MainBlock}" Grid.Row="0" Grid.Column="1" />
<Label Content="Subblock:" Grid.Row="1" />
<logic:BlockPresenter Block="{Binding SubBlock}" Grid.Row="1" Grid.Column="1" />
</Grid>
更改默认模型的主块或子块类型时,模型内的值(MainBlock或SubBlock属性)不会更新以反映新选择的块。
我知道一种解决方案是在设置新值时从BlockPresenter引发一个自定义事件(例如BlockChanged),将该值作为事件args传递,然后在DefaultModelControl.xaml.cs文件中捕获此事件并设置属性添加到新引用。
我想知道是否还有另一种方法可以在没有监听器的情况下执行此操作,因为必须为我想要的每个块演示者创建它们都是很烦人的。
我要解决这个问题吗?希望听到人们对此的建设性想法。谢谢:)