Jonathan
Jonathan

Reputation: 585

WPF Usercontrol Items not showing

I have a bar chart which is built in wpf. The user specifies the items inside the bar.

BarChart.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();
    }
}

BarChart.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()
    {

    }

}

To add a new BarChart you run

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

Yet according to the output no items have been added. What am I doing wrong and is there a better way?

Upvotes: 1

Views: 1979

Answers (3)

Ra&#250;l Ota&#241;o
Ra&#250;l Ota&#241;o

Reputation: 4760

Also i think you could do this using an ObservableCollection<BarItem> and then register to the event CollectionChanged for controlling the insertions and deletes.

But I think the right way for doing this, is using a DependencyProperty of ICollection, then if the collection implements the ICollectionChanged interface you could control the insertion and deletions for updating the view.This should be very useful if you may want make bindings to this collection.

Hope this could helps to you,...

Upvotes: 2

skink
skink

Reputation: 5736

I would do that with Binding. The code-behind would be just holding a property:

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

While UI would be doing the rest:

<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>

What has been changed in UI:

  • ItemsControl, unlike Grid, has useful ItemsSource property, which makes things easier;
  • StackPanel, unlike Grid, eliminates the need to position items manually by stacking them. You can set local:Bar Margin to a constant value if you want to have a gap between the items.

Upvotes: 1

Peter Hansen
Peter Hansen

Reputation: 8907

Your problem is that the property setter never actually is being called.

Adding the BarItem objects the way you are doing in XAML, will add the items to the existing list instance. The property setter is only being called when you set the list to a new instance.

So I would create a new list in the code-behind, and set the property there. Doing that will call the setter, and your code will run. You might need to give the BarChart a name so you can reference it.

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>

Code-behind

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

Upvotes: 2

Related Questions