首先,我在
UserControl
项目中制作了一个 WPF
,用于在设置窗口中设置颜色。
Window 有一个名为
MainWindowViewModel.cs
的 ViewModel,其中包含:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Windows.Media;
namespace integrate.vsto.planning.settings.wpf.Viewmodels
{
/// <summary>
/// The Viewmodel used in the MainWindow
/// </summary>
public class MainWindowViewModel : INotifyPropertyChanged
{
#region Fields (Border color)
/// <summary>
/// Red value (0-255) of the border color
/// </summary>
private byte _borderColorR { get; set; } = 200;
/// <summary>
/// Green value (0-255) of the border color
/// </summary>
private byte _borderColorG { get; set; } = 200;
/// <summary>
/// Blue value (0-255) of the border color
/// </summary>
private byte _borderColorB { get; set; } = 200;
#endregion
#region Properties (Border color)
/// <summary>
/// Red value (0-255) of the border color
/// </summary>
public byte BorderColorR
{
get { return _borderColorR; }
set
{
_borderColorR = value;
OnPropertyChanged(nameof(BorderColorR));
OnPropertyChanged(nameof(BorderColorBrush));
}
}
/// <summary>
/// Green value (0-255) of the border color
/// </summary>
public byte BorderColorG
{
get { return _borderColorG; }
set
{
_borderColorG = value;
OnPropertyChanged(nameof(BorderColorG));
OnPropertyChanged(nameof(BorderColorBrush));
}
}
/// <summary>
/// Blue value (0-255) of the border color
/// </summary>
public byte BorderColorB
{
get { return _borderColorB; }
set
{
_borderColorB = value;
OnPropertyChanged(nameof(BorderColorB));
OnPropertyChanged(nameof(BorderColorBrush));
}
}
/// <summary>
/// WPF compatible color for any element containing an implementation for a Brush
/// </summary>
public Brush BorderColorBrush
{
get
{
return new SolidColorBrush(Color.FromRgb(BorderColorR, BorderColorG, BorderColorB));
}
}
#endregion
#region Events
/// <summary>
/// The event triggered on any Property changed
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Fires the PropertyChanged event for the given property (by name)
/// </summary>
/// <param name="propertyName">Given property name</param>
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
此视图模型包含的内容比给定的代码多得多,并且对于不包含用户控件交互的所有内容都可以正常工作,例如普通文本框中呈现的文本和其他字节。所以我的 MainWindow 和 Viewmodel 之间的链接已正确设置,如
this.DataContext = new MainWindowViewModel();
然后是名为
ColorSettingUserControl
的 UserControl
using integrate.vsto.planning.settings.wpf.Viewmodels;
using System.Windows;
using System.Windows.Controls;
namespace integrate.vsto.planning.settings.wpf
{
/// <summary>
/// Interaction logic for ColorSettingUserControl.xaml
/// </summary>
public partial class ColorSettingUserControl : UserControl
{
/// <summary>
/// The viewmodel for the color settings user control
/// </summary>
private ColorSettingViewModel _viewmodel;
#region Attribute Registry
/// <summary>
/// The red value (0-255) for the preview control
/// </summary>
public static readonly DependencyProperty RedProperty =
DependencyProperty.Register(nameof(Red), typeof(byte), typeof(ColorSettingUserControl), new FrameworkPropertyMetadata((byte)0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnRedPropertyChanged))
/// <summary>
/// The green value (0-255) for the preview control
/// </summary>
public static readonly DependencyProperty GreenProperty =
DependencyProperty.Register(nameof(Green), typeof(byte), typeof(ColorSettingUserControl), new FrameworkPropertyMetadata((byte)0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnGreenPropertyChanged))
/// <summary>
/// The blue value (0-255) for the preview control
/// </summary>
public static readonly DependencyProperty BlueProperty =
DependencyProperty.Register(nameof(Blue), typeof(byte), typeof(ColorSettingUserControl), new FrameworkPropertyMetadata((byte)0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBluePropertyChanged))
#endregion
#region Attribute Properties
/// <summary>
/// Color value red (0-255)
/// </summary>
public byte Red
{
get { return (byte)GetValue(RedProperty); }
set { _viewmodel.Red = value; SetValue(RedProperty, value); }
}
/// <summary>
/// Color value green (0-255)
/// </summary>
public byte Green
{
get { return (byte)GetValue(GreenProperty); }
set { _viewmodel.Green = value; SetValue(GreenProperty, value); }
}
/// <summary>
/// Color value blue (0-255)
/// </summary>
public byte Blue
{
get { return (byte)GetValue(BlueProperty); }
set { _viewmodel.Blue = value; SetValue(BlueProperty, value); }
}
#endregion
}
}
最后,这是我需要工作的 UserControl 中的 XAML 行:
<UserControl x:Class="integrate.vsto.planning.settings.wpf.ColorSettingControl"
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:integrate.vsto.planning.settings.wpf"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="800">
<TextBox x:Name="txt_R" Text="{Binding Rood}" Width="46" />
<TextBox x:Name="txt_G" Text="{Binding Green}" Width="46" />
<TextBox x:Name="txt_B" Text="{Binding Blue}" Width="46" />
</UserControl>
然后是 MainWindow 实现 UserControl 的 XAML
<local:ColorSettingUserControl
Red="{Binding BorderColorR}"
Green="{Binding BorderColorG}"
Blue="{Binding BorderColorB}" />
所以我没有将
BorderColorR
的实际值从主窗口的视图模型获取到用户的控件文本框中。调试时,调试器也不会停止在公共字节红色的设置器中,也不会停止在绿色或蓝色的设置器中。
不确定我需要朝哪个方向进行研究才能使这项工作成功。
我尝试在
PropertyMetadata
中使用 FrameworkPropertyMetadata
而不是 ColorSettingUserControl.cs
作为依赖属性。
当尝试不带 Binding 的值时,如
<ColorSettingUserControl Red="20" />
,它实际上会触发 DependencyProperty 的 setter。
我希望
<ColorSettingUserControl Red={Binding BorderColorR} />
触发 DependencyProperty 的 setter,它在其私有声明中具有默认值。
您在
UserControl
内的绑定是错误的。他们使用 DataContext
作为数据源,这是错误的。他们必须使用 UserControl
作为数据源。
您可以通过使用
Bindig.RelativeSource
(或者性能更好的 Binding.ElementName
)来实现此目的:
<UserControl x:Name="Root">
<!-- Option #1: Use Bindig.RelativeSource -->
<TextBox x:Name="txt_R" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Red}" Width="46" />
<!-- Option #2: Use Binding.ElementName -->
<TextBox x:Name="txt_G" Text="{Binding ElementName=Root, Path=Green}" Width="46" />
<TextBox x:Name="txt_B" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Blue}" Width="46" />
</UserControl>