我正在尝试使用WPF Toolkit PropertyGrid在ReactiveUI中的ViewModel上显示属性。由于Reasons™,其中一个属性是自定义Size结构:
Size.cs
public struct Size
{
public float Width { get; set; }
public float Height { get; set; }
}
我的ViewModel公开了哪些内容:
ElementViewModel.cs
public class ElementViewModel : ReactiveObject
{
private Size _size;
public Size Size
{
get => _size;
set => this.RaiseAndSetIfChanged(ref _size, value);
}
}
我使用自定义控件作为编辑器,它只使用两个DoubleUpDowns作为宽度和高度,并手动更新绑定属性:
ElementSizeEditor.xaml
<UserControl x:Class="MyProject.Controls.ElementSizeEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
<Grid>
<StackPanel Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Left" Orientation="Horizontal">
<xctk:DoubleUpDown Width="75" TextAlignment="Right" VerticalContentAlignment="Center"
Name="WidthEntry" AllowTextInput="True"
ShowButtonSpinner="False" FormatString="0.###" />
<TextBlock Text="" x " />
<xctk:DoubleUpDown Width="75" TextAlignment="Right" VerticalContentAlignment="Center"
Name="HeightEntry" AllowTextInput="True"
ShowButtonSpinner="False" FormatString="0.###" />
<TextBlock Text=""" />
</StackPanel>
</Grid>
</UserControl>
ElementSizeEditor.xaml.cs
public partial class ElementSizeEditor : UserControl
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(Size),
typeof(ElementSizeEditor),
new PropertyMetadata(ValueChanged));
// manually set the values on the width and height editors when we have a new Size
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
Size size = (Size)args.NewValue;
ElementSizeEditor editor = (ElementSizeEditor)d;
editor.WidthEntry.Value = size.Width;
editor.HeightEntry.Value = size.Height;
}
public Size Value
{
get { return (Size)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public ElementSizeEditor()
{
InitializeComponent();
WidthEntry.ValueChanged += ValueChangedHandler;
HeightEntry.ValueChanged += ValueChangedHandler;
}
// manually listen to value changes because we provide a new Size instance for new values
private void ValueChangedHandler(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (WidthEntry.Value.HasValue && HeightEntry.Value.HasValue &&
(!Core.Util.Math.AreEquivalent((float)WidthEntry.Value, Value.Width) ||
!Core.Util.Math.AreEquivalent((float)HeightEntry.Value, Value.Height)))
Value = new Size((float)WidthEntry.Value.Value, (float)HeightEntry.Value.Value);
}
}
我将ElementSizeEditor注册为app-wide静态资源:
的App.xaml
<Application.Resources>
<DataTemplate x:Key="ElementSizeEditor">
<controls:ElementSizeEditor Value="{Binding Path=Value}"/>
</DataTemplate>
</Application.Resources>
并在我的属性视图中使用它:
ElementPropertiesView.xaml
<UserControl x:Class="MyProject.Views.ElementPropertiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
<Grid>
<xctk:PropertyGrid SelectedObject="{Binding}" SelectedObjectName="" SelectedObjectTypeName="{Binding Path=Name}" Grid.Row="0" AutoGenerateProperties="False"
ShowAdvancedOptions="False" ShowSortOptions="False" ShowSearchBox="False">
<xctk:PropertyGrid.EditorDefinitions>
<xctk:EditorTemplateDefinition TargetProperties="Size" EditingTemplate="{StaticResource ElementSizeEditor}" />
</xctk:PropertyGrid.EditorDefinitions>
<xctk:PropertyGrid.PropertyDefinitions>
<xctk:PropertyDefinition TargetProperties="Size" DisplayName="Size" Description="The Element's size" />
</xctk:PropertyGrid.PropertyDefinitions>
</xctk:PropertyGrid>
</Grid>
</UserControl>
在代码隐藏中适当绑定:
ElementPropertiesView.xaml.cs
public partial class ElementPropertiesView : UserControl, IViewFor<ElementViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel",
typeof(ElementViewModel),
typeof(ElementPropertiesView));
public ElementPropertiesView()
{
InitializeComponent();
this.WhenActivated(d =>
{
d(this.WhenAnyValue(_ => _.ViewModel).BindTo(this, _ => _.DataContext));
});
}
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (ColorElementViewModel)value; }
}
public ElementViewModel ViewModel
{
get { return (ColorElementViewModel) GetValue(ViewModelProperty); }
set
{
SetValue(ViewModelProperty, value);
}
}
}
当我加载属性视图时,它正确地将ElementViewModel绑定到PropertyGrid的SelectedObject
,正确显示Size属性的ElementSizeEditor,正确绑定到ElementSizeEditor中的值,并在用户时正确更新ValueProperty输入新值。
它没有做的是将新的Size值反馈回ElementViewModel,我很难过为什么。我在其他情况下通过编写一个暴露的辅助类来解决这个问题,并知道如何进入ElementViewModel以更新相关属性,但这些实例更有意义,因为需要额外的功能。这次我只想用新的Size更新ViewModel。
答案 0 :(得分:0)
这很可能是因为您应该将 DataTemplate 上的绑定模式设置为 TwoWay。也就是说,在 App.xaml 中,您应该将