【问题标题】:WPF User Control property not getting valueWPF用户控件属性没有获得价值
【发布时间】:2015-02-17 14:16:27
【问题描述】:

我正在尝试创建一个非常简单的 WPF 用户控件来表示数字时钟。

我有几件事希望客户端代码能够更改,例如前景文本颜色、字体等,所以我为它们创建了一些公共属性。部分代码如下所示:

    public partial class DigitalClock : System.Windows.Controls.UserControl
    {
        public string Color { get; set; }

        private Timer timer;            
        private string DisplayString { get { return DateTime.Now.ToString("dd-MM-yy HH:mm:ss"); } }

        public DigitalClock()
        {
            InitializeComponent();                    
            this.timer = new Timer();                
            this.timer.Tick += new EventHandler(UpdateClock);
            this.timer.Interval = 1000;
            this.timer.Enabled = true;
            this.timer.Start();
            UpdateClock(null, null);

            try
            {
                //exception thrown here as this.Color is null
                Color color = (Color)ColorConverter.ConvertFromString(this.Color);
                tbClock.Foreground = new SolidColorBrush(color);                                    
            }
            catch (Exception ex)
            {
                Console.WriteLine(">>>" + ex.Message);
            }
        }

        private void UpdateClock(object sender, EventArgs e)
        {
            tbClock.Text = DisplayString;
        }
    }
}

我在这样的另一个页面上使用它:

<CustomControls:DigitalClock color="#ff000000" />

没有语法错误,时钟出现在屏幕上,但每当代码到达尝试设置颜色的行时,我就会得到一个Object reference is not set to an instance of an object

我认为这与设置 Color 属性的时间点有关,因为在计时器的第一个“滴答”之后,该值不再为空。我该如何解决这个问题?

【问题讨论】:

  • 尝试在构造函数中将默认值设置为Color。
  • 为什么不在 XAML 中设置颜色?或者只是在构造函数中设置它。另外,如果你按照你已经做的方式做,你不能在分配它之前输入一行:if (color!=null)
  • 尝试添加 Usercontrol Loaded 方法并将其设置在那里?
  • 您的 XAML 的执行方式类似于:var ctl = new DigitalClock(); ctl.Color = #ff000000;。构造函数代码在第一行运行,此时 Color 属性为null。尝试改用Loaded 事件或Color 属性的设置器。另外,我会使用 DependencyProperty 进行调查以允许绑定:)

标签: c# .net wpf


【解决方案1】:

当您将控件插入另一个 XAML 文档时,从该文档设置的属性将在您的控件实例化后设置,这意味着在调用您的构造函数时,您可能已经设置了 Colorproperty您的其他 XAML 文档仍具有其默认值。

你可以做任何你想做的事:

  • 监听你的控件的Loaded事件(见https://msdn.microsoft.com/en-us/library/ms742302%28v=vs.110%29.aspx),这将在控件实例的所有属性设置后被调用(你可能想在这里启动你的定时器,然后停止它在Unloaded 事件中确保当控件未在屏幕上实例化时它不会打勾),

  • 您可以为Color 属性的设置器编写一个主体来传播更改:

public string Color
{
  set { tbClock.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value)); }
}
  • 如果您想从另一个 XAML 文档设置颜色,您还可以提供 Brush 类型的属性而不是颜色:
public Brush ClockForeground
{
    get { return tnClock.Foreground; }
    set { tnClock.Foreground = value; }
}

因此,在您的其他 XAML 文档中,您可以通过让 XAML 解析器自动将颜色名称转换为画笔来直接设置颜色:

<local:DigitalClock ClockForeground="Yellow" />
  • 或者更好的是,您可以在控件上声明一个依赖属性并使用数据绑定(假设这里tbClockTextBlock):
public Brush ClockForeground
{
    get { return (Brush)GetValue(ClockForegroundProperty); }
    set { SetValue(ClockForegroundProperty, value); }
}
public static readonly DependencyProperty ClockForegroundProperty = DependencyProperty.Register("ClockForeground", typeof(Brush), typeof(DigitalClock));

public DigitalClock()
{
    InitializeComponents();
    ...
    BindingOperations.SetBinding(tbClock, TextBlock.ForegroundProperty, new Binding
    {
        Source = this,
        Path = new PropertyPath(ClockForegroundProperty)
    });
}

【讨论】:

    【解决方案2】:

    您不应将属性声明为 CLR 属性。您应该改为创建依赖属性,默认情况下允许您绑定、验证等等。看看这个:http://www.codeproject.com/Articles/32825/How-to-Creating-a-WPF-User-Control-using-it-in-a-W。在您的示例句柄事件中加载如下:

      this.Loaded += DigitalClock_Loaded;
     void DigitalClock_Loaded(object sender, RoutedEventArgs e)
            {
                    //your actions
                    Color color = (Color)ColorConverter.ConvertFromString(this.Color);
            }
    

    属性尚未绑定到构造函数中。

    【讨论】:

    • 谢谢,这似乎有效。正如您所提到的,WPF 必须在构造函数之后绑定属性。
    【解决方案3】:

    不要在构造函数中分配颜色,因为它总是 null 因为在实例化对象之前不会设置属性,使用支持字段的Color 属性的设置器似乎更好。

    另外,请注意,在这种情况下您应该使用依赖属性,并利用绑定。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多