-2

In a WPF form .NET framework, I'm trying to achieve the following (seemingly) simple task:

I have 3 buttons and 3 textboxes:
Button 1 Textbox1
Button 2 Textbox2
Button 3 Textbox3

If I click button 1, I want textbox 1 to read true and the other 2 false. If I click button 2, I want textbox 2 to show true and the others false and the same for button 3 and textbox 3 respectively.

I thought I could achieve this by setting the value of all of the Booleans to either true or false depending on the button that has been clicked using the click event, but don't get the expected result

using System;
using System.Windows;
using System.Threading;
using System.Windows.Threading;


namespace WPF_Test
{

    public partial class MainWindow : Window
    {
        bool value1;
        bool value2;
        bool value3;
             
        public MainWindow()
        {
            InitializeComponent();

            if (value1 == true)
             {
               textbox1.Text = value1.ToString();
             } else if (value2 == true){
               textbox2.Text = value2.ToString();
             } else if (value3 == true){
               textbox3.Text = value3.ToString();
             }
        }                                                        

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            value1 = true;
            value2 = false;
            value3 = false;
        }

        private  void button2_Click(object sender, RoutedEventArgs e)
        {
            value1 = false;
            value2 = true;
            value3 = false;
        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            value1 = false;
            value2 = false;
            value3 = true;
        }
    }
}

Any idea what I might be missing?

greybeard
  • 2,249
  • 8
  • 30
  • 66
Quinten
  • 1
  • 3
  • Just move the code in the constructor after `InitializeComponent` to the separate method and then call it at the bottom each `Button.Click` event handler. – Rekshino May 09 '21 at 20:53
  • @Rekshino thank you that was what I was looking for. However, I'm wondering why @D M replied with the INotifyPrpertyChanged part? Is that a 'safer' way of doing things? – Quinten May 10 '21 at 09:21
  • 1
    WPF was thought to be used mainly with MVVM, developers try to avoid code behind coding. – Rekshino May 10 '21 at 09:27
  • @Rekshino is correct, I would personally avoid using the codebehind to change a property on the UI directly. I also missed that you were not binding the values. As Rekshino said, if you're okay with keeping logic in the codebehind, you can set the value of the `TextBox` by setting the value of `TextBox.Text` directly as you are doing in the constructor. – D M May 10 '21 at 13:20
  • Why isn't this just 3 radio buttons in a stackpanel? You click one l, it'll be set ischecked true and the rest ischecked false. If you really mudt have the words rather than a spot then i think you can probably just bind the content of the radiobuttons to their ischecked property. – Andy May 10 '21 at 19:56
  • @Andy the goal was to get an understanding of some other code I was working on and this solved it. Haven't worked with stackpanels/radio buttons but by the sounds of it that also works if this was the only goal. – Quinten May 11 '21 at 13:11

2 Answers2

0

referencing Rekshino's comment:

Just move the code in the constructor after InitializeComponent to the separate method and then call it at the bottom each Button.Click event handler. – Rekshino

however, my limited knowledge does not certify that this is the 'best' version so for this I refer to D M's answer as well

Quinten
  • 1
  • 3
-3

In order to update the UI in WPF by binding to a value in the code behind, you need to change the fields to properties and implement the INotifyPropertyChanged interface. There's a really good answer on how to do this by Marc Gravell.

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private bool _value1;
    public bool value1 
    {
        get => _value1;
        set => SetField(ref _value1, value);
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        value1 = true;
    }


    // Implementation of INotifyPropertyChanged with a
    // SetField helper method to ensure you're only
    // notifying when a value actually changes.

    public event PropertyChangedEventHandler? PropertyChanged;

    protected void OnPropertyChanged(string? propertyName) 
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}
D M
  • 5,769
  • 4
  • 12
  • 27
  • hmm ok, not as simple as I thought it would be. I'll study your suggestion, thank you. – Quinten May 09 '21 at 18:52
  • It's not a simple topic and, depending on your needs, you can get away with modifying the UI directly from the codebehind. But if you're trying to learn WPF and intend to take full advantage of it, `INotifyPropertyChanged` is something you'll need to learn eventually. Binding is fundamental to the framework. – D M May 10 '21 at 13:23
  • I see, thank you. Don't fully understand it yet, but I feel I'm getting an idea why this would be used. – Quinten May 11 '21 at 13:13