Sss
Sss

Reputation: 1529

How to set position of combobox in c# using silverlight5

I am c# and silverlight beginner and i have a situation where i dynamically create combo box and add it in list.

if (p.Component.Type == "Combo")
  {
    var cb = new ComboBox();
    foreach (var item in p.Component.Attributes.Items)
      {
        cb.Items.Add(item);  //These item contains a l0,15,45,60 to select through combo box

      }
    result.Add(cb);                    
  } 

I have many other things like "TextBlock","TextBox" etc. things to add in this list. Suppose i also have to add this TextBlock in same list with one more if condition like this :

 if (true)
 {
     var txtblk = new TextBlock();
     txtblk.Text = "Max Amount";
     result.Add(txtblk);
  }

Now the outout obtained is like this : enter image description here I mean it is always at Top=Left=0. (I mean they overlaps)

Now question is how to give these GUI elements different position in the same list ? Please do not hesitate to ask me if you still don't understand the question.

Note: I am using silverlight5 My xaml code is (My container is canvas) :

<UserControl x:Class="RenderingTest.MainPage"
    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:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:this="clr-namespace:RenderingTest.Converters"
             xmlns:sdh="clr-namespace:RenderingTest"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>
        <this:MyValueConverter x:Key="TabConverter"/>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="Green">
        <sdh:MyItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay, Converter={StaticResource TabConverter}}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="Gray">  </Canvas>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border Width="150" Background="red" Height="100" Canvas.Left="10"  Canvas.Top="100"  >
                        <ContentPresenter/>
                    </Border> 
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </sdh:MyItemsControl>
    </Grid>

</UserControl>

EDIT: I have added the photo of GUI which is supposed to be achieved and also the xml i deserialized(which i am sure that it is properly deserialized i can see that on debugging) (here Parameter is parent class)

EDIT2 (after thbe new answer):

My parameter.cs class is:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.Runtime;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Collections;
namespace RenderingTest
{
    [XmlRoot(ElementName = "parameter")]
    public class Parameter
    {
        [XmlElement("name")]
        public string Name { get; set; }
        [XmlElement("label")]
        public string Label { get; set; }
        [XmlElement("unit")]
        public string Unit { get; set; }
        [XmlElement("component")]
        public Component Component { get; set; }
    }
}

ViewModel.cs is : (please note that in ReadParameterXML() i pass the xml string in its parameter from MainPage.cs class)

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Runtime;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Collections;
using System.Collections.ObjectModel;


namespace RenderingTest
{
    public class viewModel : GenericViewModel
    {

        private ObservableCollection<Parameter> tabList;
        public ObservableCollection<Parameter> TabList
        {

            get { return tabList; }
            set
            {
                tabList = value;
                OnPropertyChanged("TabList");
            }
        }


        #region Constructor
        public viewModel()        
        {
            tabList = new ObservableCollection<Parameter>();
        }
        #endregion

        public void ReadParameterXML(String xmlstring)
        {


            XmlSerializer deserializer = new XmlSerializer(typeof(Parameter));
            XmlReader reader = XmlReader.Create(new StringReader(xmlstring));
            Parameter parameter = (Parameter)deserializer.Deserialize(reader);
            foreach (var item in parameter.Component.Attributes.Items)
            {
                Debug.WriteLine(item);
            }
            tabList.Add(parameter);
            Debug.WriteLine(parameter.Component.Type);
            Debug.WriteLine(parameter.Name);
            Debug.WriteLine(parameter.Label);
            Debug.WriteLine(parameter.Unit);
        }

    }
}

MyConverter.cs is

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Diagnostics;
using System.Collections.Generic;

namespace RenderingTest.Converters
{
    public class MyValueConverter : IValueConverter
    {
        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            ICollection<Parameter> list = value as ICollection<Parameter>;
            List<UIElement> result = new List<UIElement>();    
                if (list != null)
                {
                    foreach (Parameter p in list)
                    {                
                        if (p.Component.Type == "Combo")
                        {
                            StackPanel st = new StackPanel()
                            {
                                Orientation = Orientation.Horizontal
                            };

                            var txtblk = new TextBlock();
                            var txtblk2 = new TextBox();
                            txtblk.Text = p.Label;
                            var cb = new ComboBox();
                            foreach (var item in p.Component.Attributes.Items)
                            {
                                cb.Items.Add(item);  //These item contains a l0,15,45,60 to select through combo box                                
                            }
                            cb.SelectedIndex = cb.Items.Count - 1;
                            txtblk2.Text = cb.SelectedValue.ToString() +" millions";
                            st.Children.Add(txtblk);
                            st.Children.Add(cb);
                            st.Children.Add(txtblk2);
                         //  Canvas.SetTop(cb, itemHeight * i++);
                            result.Add(st);
                        }
                    }
                }
            return(result);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        #endregion

    }
}

MainPage.Xaml is

<UserControl x:Class="RenderingTest.MainPage"
    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:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:this="clr-namespace:RenderingTest.Converters"
             xmlns:sdh="clr-namespace:RenderingTest"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>
        <this:MyValueConverter x:Key="TabConverter"/>
    </UserControl.Resources>



    <Grid x:Name="LayoutRoot" Background="Green">
        <sdh:MyItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay, Converter={StaticResource TabConverter}}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="Gray"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border Width="150" Background="red" Height="100" Canvas.Left="50"  Canvas.Top="100"  >
                        <ContentPresenter/>
                    </Border> 
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </sdh:MyItemsControl>
    </Grid>

</UserControl>

Upvotes: 1

Views: 585

Answers (2)

Mashton
Mashton

Reputation: 6415

Ok, from your edit one possible approach is:

  • Create a class which represents your 'parameter' structure. How many different arrangements of this class are you likely to have? Are they all of the form NameString, List<T>, UnitsString or are there other forms? If there are a range of these types then consider how much similarity there actually is, and whether they should be represented as one class or a few derived classes.
  • In your ViewModel build up a collection of these parameter classes, and bind that collection to an items control in your View
  • Define the item template of your items control so that it creates/displays the properties of a parameter class with the appropriate UI elements (i.e. NameString and UnitsString properties displayed in a TextBlock, List displayed in a ComboBox)

But the gist of it is:

  • Stop thinking that your data is UI. It isn't. It is data, and should be represented as such ... as a class or classes.
  • Then start thinking how best to represent a class of data (or classes of data) with UI elements.
  • If there are an unknown number of these classes to show in the UI then you will need to decide what kind of layout should you use ... maybe all of them in a list one after the other? In which case use binding and create a collection of these classes, which will be bound to the ItemsSource of an ItemsCollection UI component. Define the item template for this UI component to further bind the properties within your class to a specific kind of UI component appropriate to the kind of property you're dealing with.

Upvotes: 1

McGarnagle
McGarnagle

Reputation: 102753

Take a look at some of the built-in panel controls. Choosing one of these and using it correctly is a good starting point to creating a layout for your view. A good one to start with is the StackPanel -- that adds each child control underneath the previous one.

Right now you're using the Canvas panel, which could also work, but you are not using it correctly. A Canvas needs each child element to define its Canvas.Left and Canvas.Top attached properties.

You're also making your life more difficult by using code-behind to construct a UI, rather than using XAML. You might want research data binding (starter example here), which is the core of Silverlight, before you undertake to build an app.


Edit

Here are two minimal examples of how you would position your items.

Option 1

Use a panel that automatically places its children:

<ItemsPanelTemplate>
    <StackPanel Background="Gray" />
</ItemsPanelTemplate>

Option 2

If you're sure you want to use a Canvas, then you'll need to set Canvas.Left and/or Canvas.Top on each of the children. Here's a basic example of how, using Canvas.SetTop:

int i=0;
double itemHeight = 30;

if (p.Component.Type == "Combo")
{
    var cb = new ComboBox();
    foreach (var item in p.Component.Attributes.Items)
    {
        cb.Items.Add(item);  //These item contains a l0,15,45,60 to select through combo box
    }
    Canvas.SetTop(cb, itemHeight * i++);
    result.Add(cb);                    
} 
var txtblk = new TextBlock();
txtblk.Text = "Max Amount";
Canvas.SetTop(txtblk, itemHeight * i++);
result.Add(txtblk);

Upvotes: 1

Related Questions