gpt4 book ai didi

wpf - 当 UI 值更改时,将 ViewModel 上的结构属性绑定(bind)到 WPF 工具包 PropertyGrid 不会更新 ViewModel

转载 作者:行者123 更新时间:2023-12-03 10:42:42 25 4
gpt4 key购买 nike

我正在尝试使用 WPF Toolkit PropertyGrid 在 ReactiveUI 中的 ViewModel 上显示属性。由于 Reasons™,这些属性之一是自定义 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 作为宽度和高度,并手动更新绑定(bind)属性:

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="&quot; x " />
<xctk:DoubleUpDown Width="75" TextAlignment="Right" VerticalContentAlignment="Center"
Name="HeightEntry" AllowTextInput="True"
ShowButtonSpinner="False" FormatString="0.###" />
<TextBlock Text="&quot;" />
</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 注册为应用程序范围的静态资源:

应用程序.xaml
<Application.Resources>
<DataTemplate x:Key="ElementSizeEditor">
<controls:ElementSizeEditor Value="{Binding Path=Value}"/>
</DataTemplate>
</Application.Resources>

并在我的属性 View 中使用它:

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>

在代码隐藏中适本地绑定(bind):

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);
}
}
}

当我加载属性 View 时,它将 ElementViewModel 正确绑定(bind)到 PropertyGrid 的 SelectedObject ,正确显示 Size 属性的 ElementSizeEditor,正确绑定(bind)到 ElementSizeEditor 中的 Value,并在用户输入新值时正确更新 ValueProperty。

它没有做的是将新的 Size 值反馈回 ElementViewModel,我不知道为什么。在其他情况下,我通过编写一个帮助程序类来解决这个问题,该类被公开并且知道如何进入 ElementViewModel 以更新关联的属性,但是这些实例更有意义,因为需要额外的功能。这次我只想用新的 Size 更新 ViewModel。

最佳答案

这很可能是因为您应该将 DataTemplate 上的绑定(bind)模式设置为 TwoWay。也就是说,在App.xaml中,应该将 改为

关于wpf - 当 UI 值更改时,将 ViewModel 上的结构属性绑定(bind)到 WPF 工具包 PropertyGrid 不会更新 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47972526/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com