Search code examples
c#wpftextboxviewmodel

User Input for polynomial functions


I need to create an application where the user can enter different polynomial functions. First the user has to select a certain grade of the polynomial function (between 0 and 10). On the basis of the selected grade there should appear different amount of textboxes where the user can specify the values for the coefficients. For example the user selects grade "4" -> 5 textboxes appear. It should look like this:

a4___ a3___ a2___ a1___ a0___

___: stands for a single textbox

I am also struggling to align the textboxes horizontally when using an ItemsControl. I also want to save the values entered by the user in my ViewModel. I have already tried so many things but i can't figure it out how to do it. This is my code so far:

<ItemsControl ItemsSource="{Binding SelectedGrade}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Height="20" Width="100"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

public ObservableCollection<double> SelectedGrade
    {
        get
        {
            ObservableCollection<double> newCol = new ObservableCollection<double>();
            for (int i = 0; i < this.SelectedNum + 1; i++)
            {
                newCol.Add(0);
            }

            this.selectedGrade = newCol;
            return newCol;
        }
        set
        {
            //...
        }
    }


public ICommand AddPolyFuncCommand
    {
        get
        {
            return new Command(obj =>
            {
                Function newPolyFunc = new PolyFunction(this.Coefficients);
                Functions.Add(newPolyFunc);
                CalculatePoints();
            });
        }
    }

Solution

  • According to the Comments i'll provide a small Example how it could be done (i've added 1-2 extras which may be handy for this)

    Use Text="{Binding Value}" to bind to the Value in the VM

    Use a Wrappanel to display it horizontally

    (optional) Use the AlternationIndex to label the Coefficients

    (optional) Change the FlowDirection to display it like you sketched it

    <!-- Combobox to select from the available Grades and store the selected in the SelectedGrade -->
    <ComboBox ItemsSource="{Binding AvailableGrades}" SelectedValue="{Binding SelectedGrade}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
    
    <!-- Use Alternationcount to label the coefficients properly and Flowdirection to keep a0 on the right side -->
    <ItemsControl ItemsSource="{Binding Coefficients}" AlternationCount="11" FlowDirection="RightToLeft">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <!-- Textbox to enter Coefficient (eg. a0 would be SelectedGrade[0] in code)-->
                    <TextBox Text="{Binding Value}" Width="50" VerticalAlignment="Center"/>
                    <!-- Labeling of the Coefficient using the AlternationIndex and a String Format -->
                    <Label Content="{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource TemplatedParent}}" ContentStringFormat="a{0}"/>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <!--  Use a WrapPanel as ItemsPanel to align the Entries horizontally -->
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
    

    And looks like this (without the Grade Textbox, solely the stuff on the right side) enter image description here


    EDIT

    To adjust the amount of coefficients properly there is a little bit logic needed, but first -> Rename the Properties appropriately and define their possible value (this helps to create the appropriate logic to the Properties)

    AvailableGrades = 0, 1, 2 ... 10

    SelectedGrade ∈ {0, 1, 2 ... 10}

    Coefficients = a(0), a(1) ... a(SelectedGrade)

    //Unfortunately it is not possible to use a Value Type and bind to it due it has no Getter/Setter therefore we need a little wrapper
    public class ValueTypeAsClass<T>
    {
        public T Value { get; set; }
        public static implicit operator ValueTypeAsClass<T>(T v)
        {
            return new ValueTypeAsClass<T> { Value = v };
        }
        public static implicit operator T(ValueTypeAsClass<T> v)
        {
            return v.Value;
        }
    }
    
    //member variable for select grade
    private int _selectedGrade = 0;
    //List of Coefficients (renamed from SelectedGrade)
    public ObservableCollection<ValueTypeAsClass<double>> Coefficients { get; set; } = new ObservableCollection<ValueTypeAsClass<double>>() { 0d };
    //Available (valid) Grades to select from in the ComboBox
    public List<int> AvailableGrades { get; private set; } = Enumerable.Range(0, 11).ToList();
    //Currently selected grad with logic to adjust the coefficient amount
    public int SelectedGrade
    {
        get { return _selectedGrade; }
        set
        {
            _selectedGrade = value;
            //Clear Coefficients and add the necessary amount
            Coefficients.Clear();
            for (int i = 0; i <= _selectedGrade; i++) { Coefficients.Add(0); }
        }
    }