【问题标题】:Literal value for custom property is null自定义属性的字面值是 null
【发布时间】:2017-11-29 14:12:00
【问题描述】:

我使用用户控件创建了一个标签栏,因为我需要标签栏位于多个页面上,因为它会更改当前页面。这意味着标签栏必须通过在正确图像后面移动一个黑色矩形来显示当前显示的页面。所以我尝试使用一个名为 SelectionIndex 的自定义属性将选择矩形移动到正确图像后面,0 是主图像,1 是计划图像等。下面的代码显示了在应该选择图像的页面上使用的标签栏第二个。

    <Grid>
        <local:TabBar SelectionIndex="1" Margin="0,0,1222,0"/>
    </Grid>

下面的代码是由propdp 生成的,我把属性名改成了SelectionIndex。然后我使用 Switch-Case 检查属性的值是什么,并更改矩形图像的边距以移动它。

public partial class TabBar : UserControl
{
    public int SelectionIndex
    {
        get { return (int)GetValue(SelectionIndexProperty); }
        set { SetValue(SelectionIndexProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectionIndex.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectionIndexProperty =
        DependencyProperty.Register("SelectionIndex", typeof(int), typeof(TabBar), new PropertyMetadata(0));


    public TabBar()
    {
        InitializeComponent();

        switch (SelectionIndex)
        {
            case 0:
                SelectionBox.Margin = new Thickness(0, 10, 0, 0);
                break;
            case 1:
                SelectionBox.Margin = new Thickness(0, 123, 0, 0);
                break;
        }
    }
}

但是,我在switch (SelectionIndex) 上设置了一个断点来检查 SelectionIndex 的值,它是 0 但应该是 1。 为了自己解决这个问题,我将属性类型从 int 更改为字符串,这表明 SelectionIndex 不是“0”,而是 null。

我已经在 Google 上搜索过这个问题,但似乎其他人都无法将值绑定到属性,我只想能够在 XAML 中将属性设置为 0-5 之间的 int。

【问题讨论】:

  • 似乎 SelectionIndex 值是在 TabBar 构造器之后设置的。尝试将开关移动到另一个地方,例如“加载”
  • @AlekDepler 有效,您可以将其发布为答案以便我接受吗?谢谢,
  • @RossTinsley 不要使用 Loaded,如果第一次设置后值发生变化,它将不起作用。

标签: c# wpf user-controls dependency-properties custom-properties


【解决方案1】:

问题是你在构造函数中这样做,并且在创建控件后在属性上设置了值。

您需要在依赖属性上添加一个属性更改处理程序并调用一个方法来处理更改:

public partial class TabBar : UserControl
{
    ....
    // Using a DependencyProperty as the backing store for SelectionIndex.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectionIndexProperty =
        DependencyProperty.Register("SelectionIndex", typeof(int), typeof(TabBar), new PropertyMetadata(0, propertyChangedCallback: (d,e)=> ((TabBar)d).OnSelectionIndexChanged()));


    public void OnSelectionIndexChanged()
    {
        switch (SelectionIndex)
        {
            // ....
        }
    }
}

【讨论】:

    【解决方案2】:

    它不是空值,它是零。

    但是,狭义地说,您的麻烦在于,直到构造函数完成后才分配属性。但更广泛地说,您没有利用 WPF 让您做事的方式。

    在 WPF 中,这可以在没有太多 C# 代码的情况下完成。不要使用边距进行定位,请使用网格。通过将其Grid.Column 属性绑定到SelectedIndex,将“标记”边框定位在网格内。尽可能简单,现在您可以调整网格中项目的大小,一切都会神奇地工作。如果你想把两个东西放在第三列,最好说“把这个和那个都放在第三列”而不是“把这个放在 356 个单位偏移处”,或者在其他地方说“把这个放在呃……什么是又是第三列的偏移量?”然后您明年更改设计并忘记更新其中一个。

    <Grid>
        <Grid.ColumnDefinitions>
            <!-- Made up width values -->
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <Border
            Background="DeepSkyBlue"
            Grid.Column="{Binding SelectionIndex, RelativeSource={RelativeSource AncestorType=UserControl}}"
            >
        </Border>
        <Label Grid.Column="0">Click Me</Label>
        <Label Grid.Column="1">No, Click Me</Label>
        <Label Grid.Column="2">Me Me Me!</Label>
        <Label Grid.Column="3">Wahhhh</Label>
    </Grid>
    

    但是

    如果您想坚持原来的方法,您可以将该 switch 语句移至 Loaded 事件,但“更好”的方法是使用依赖属性上的 PropertyChanged 处理程序。这样,每当属性更改时,您的控件都会适当地响应更改。我们将默认值设为 -1,否则永远不会调用属性更改处理程序:

    public int SelectionIndex
    {
        get { return (int)GetValue(SelectionIndexProperty); }
        set { SetValue(SelectionIndexProperty, value); }
    }
    
    public static readonly DependencyProperty SelectionIndexProperty =
        DependencyProperty.Register(nameof(SelectionIndex), typeof(int), typeof(TabBar),
            new FrameworkPropertyMetadata(-1, SelectionIndex_PropertyChanged));
    
    protected static void SelectionIndex_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as TabBar).OnSelectionIndexChanged(e.OldValue);
    }
    
    private void OnSelectionIndexChanged(object oldValue)
    {
        switch (SelectionIndex)
        {
            case 0:
                SelectionBox.Margin = new Thickness(0, 10, 0, 0);
                break;
            case 1:
                SelectionBox.Margin = new Thickness(0, 123, 0, 0);
                break;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-19
      • 2019-02-25
      • 1970-01-01
      • 2022-12-10
      • 2020-12-19
      相关资源
      最近更新 更多