1

我有一个内置于 wpf 的条形图。用户指定栏内的项目。

条形图.xaml.cs

public partial class BarChart : UserControl
{
    List<BarItem> BarItems = new List<BarItem>();
    List<Bar> Bars = new List<Bar>();
    public List<BarItem> Items
    {
        get { return BarItems; }
        set
        {
            BarItems = value;
            Bars.Clear();
            int i=0;
            this.LayoutRoot.Children.Clear();
            //This line should show up but doesn't suggesting that that the property is not being set?
            Debug.WriteLine("SET");
            foreach(BarItem Item in BarItems){
                Bar ThisBar=new Bar();
                ThisBar.CurrentLable=Item.Lable;
                ThisBar.CurrentValue=Item.Value;
                Debug.WriteLine("{0}:{1} at {2}",Item.Lable,Item.Value,(i*55));
                ThisBar.CurrentX=i*55;
                this.AddChild(ThisBar);
                i++;
            }
            Debug.WriteLine(i);
        }
    }
    public BarChart()
    {
        this.InitializeComponent();
    }
}

条形图.xaml

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CipherCracker"
mc:Ignorable="d"
x:Class="CipherCracker.BarChart"
x:Name="BarChartList"
d:DesignWidth="640" d:DesignHeight="480">

<Grid x:Name="LayoutRoot"/>
</UserControl>

BarItem.cs

public class BarItem
{
    public int Value
    {
        get;
        set;
    }
    public string Lable
    {
        get;
        set;
    }
    public BarItem()
    {

    }

}

添加一个新的条形图你运行

<local:BarChart>
    <local:BarChart.Items>
        <local:BarItem Lable="B" Value="75"/>
        <local:BarItem Lable="A" Value="50"/>
    </local:BarChart.Items>
</local:BarChart>

然而,根据输出没有添加任何项目。我做错了什么,有更好的方法吗?

4

3 回答 3

2

您的问题是实际上从未调用过属性设置器。

以您在 XAML 中的方式添加 BarItem 对象,会将项目添加到现有列表实例中。仅当您将列表设置为新实例时才会调用属性设置器。

所以我会在代码隐藏中创建一个新列表,并在那里设置属性。这样做将调用 setter,您的代码将运行。您可能需要为 BarChart 命名,以便您可以引用它。

XAML

<local:BarChart x:Name="bar">
    <!-- Doing this adds BarItems to the existing list. 
    <local:BarChart.Items>
        <local:BarItem Lable="B" Value="75"/>
        <local:BarItem Lable="A" Value="50"/>
    </local:BarChart.Items>
    -->
</local:BarChart>

代码隐藏

public MainWindow()
{
    InitializeComponent();

    //Setting the Items property to a new list, will call the setter..
    bar.Items = new List<BarItem>
    {
        new BarItem { Lable = "Test1", Value = 500 }, 
        new BarItem { Lable = "Test2", Value = 1000 },
        new BarItem { Lable = "Test3", Value = 1500 }
    };
}
于 2012-11-15T18:28:12.470 回答
2

另外我认为您可以使用 anObservableCollection<BarItem>然后注册到事件CollectionChanged以控制插入和删除。

但我认为这样做的正确方法是使用DependencyPropertyof ICollection,那么如果集合实现了ICollectionChanged接口,您可以控制插入和删除以更新视图。如果您可能想要绑定到这个集合,这应该非常有用。

希望这对你有帮助,...

于 2012-11-15T19:08:11.897 回答
1

我会用绑定来做到这一点。代码隐藏将只是持有一个属性:

public partial class BarChart : UserControl
{
    private List<BarItem> _items;
    public List<BarItem> Items
    {
        get { return _items ?? (_items = new List<BarItem>()); }
        set { _items = value; }
    }

    public BarChart()
    {
        InitializeComponent();
    }
}

而 UI 将完成其余的工作:

<ItemsControl ItemsSource="{Binding Items, ElementName=BarChartList}">

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:Bar CurrentLable={Binding Lable} CurrentValue={Binding Value}/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ItemsControl>

用户界面发生了哪些变化:

  • ItemsControl与 不同Grid,具有有用的ItemsSource属性,这使事情变得更容易;
  • StackPanel与 不同Grid,无需通过堆叠手动放置物品。local:Bar Margin如果要在项目之间留出间隙,可以设置为常数值。
于 2012-11-15T19:00:23.740 回答