1

I am trying to learn databinding and new in C#. To isolate the code from UI I want to bind the value from the XAML. And I made the following example to ask my question as clear as possible:

Here is the program. I want the progress bar to increase or decrease by using increase or decrease buttons but these should be tied to "value" parameter in a class. The increaseValue method in the class Power returns value and I want to bind that value to the button and the progress bar. So when the user clicks on the button the value will increase and also the progress bar will be tied to the new value:

enter image description here

XAML code:

<Window x:Class="WpfBindingTest.MainWindow"
        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:WpfBindingTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>

        <Button x:Name="Increase" Content="Increase" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Button>
        <Button  Grid.Row="1" x:Name="Decrease" Content="Decrease" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Button>
        <ProgressBar Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="10"></ProgressBar>
        <Label Grid.Row="1" Grid.Column="1"  HorizontalAlignment="Stretch" VerticalAlignment="Center"></Label>
        
    </Grid>
</Window>

MainWindow.xaml.cs:

namespace WpfBindingTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Power power = new Power();
        public MainWindow()
        {
            InitializeComponent();          
        }
    }
}

class Power:

namespace WpfBindingTest
{
    public class Power
    {

        public int increaseValue(int value)
        {
            value++;
            return value;
        }
    }
}

I can achieve what I want by code but I want to isolate the Power class from UI but super confused about how to do data binding.

GNZ
  • 575
  • 2
  • 10
  • So I dont want to directly bind button to progressbar. But bind both button and progress bar to value in class Power. It is because the value comes from serial port. So value should dictate the progressbar value. – GNZ Jul 04 '21 at 14:51
  • Are you familiar with the MVVM Design Pattern? Anyway, if this is a bigger Application, I would stick to it/have a look into it. If you just want to know how to databind buttons, what you are looking for is probably the `ICommand` interface and the RelaisCommand class, which makes binding to Button commands pretty easy. – Roland Deschain Jul 04 '21 at 14:55
  • For some reference, [here is a small repo I made some time ago](https://github.com/TheRealRolandDeschain/DesignPatternsMVVMExample), showcasing MVVM. It is a repo with the same little program made twice, one time MVVM was used, the other time no MVVM was used. Maybe it helps :) – Roland Deschain Jul 04 '21 at 15:00
  • How am I going to use ICommand in my case? – GNZ Jul 04 '21 at 15:01
  • Small application staying away from MVVM – GNZ Jul 04 '21 at 15:01
  • OK, but the MVVM example still shows a nice way to bind to a button command using ICommand interface – Roland Deschain Jul 04 '21 at 15:02
  • It is very difficult for me MVVM. I dont need it in my case its an overkill. I don understand it. Can you bind the data in my case? How is that done? – GNZ Jul 04 '21 at 15:04
  • One moment, trying to write an answer – Roland Deschain Jul 04 '21 at 15:06
  • Your question lacks focus. It's not clear, of this multi-faceted problem, what it is _specifically_ you need help with. That said, the two main components are: binding a numeric property to the progress bar; binding a command to the button, which modifies the numeric property. See duplicate for the latter. – Peter Duniho Jul 04 '21 at 15:39
  • I know Im confused so that is why probably couldnt make it super clear. I believe I need to study more on the topic. But by this question I noticed binding isnt as simple as I was imagining. – GNZ Jul 04 '21 at 15:51

1 Answers1

0

I have currently no way to test my answer, so please take this with a grain of salt:

First of all, if you want to bind to the Power class, you have to set it as Datacontext in MainWindow.xaml.cs:

namespace WpfBindingTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Power power = new Power();
        DataContext = power;
        public MainWindow()
        {
            InitializeComponent();          
        }
    }
}

Then Add the RelaisCommand class, which inherits from ICommand to your project (you can simply copy this code:

public class RelayCommand : ICommand
    {
        #region Private Fields
        private readonly Action<object> _executeHandler;
        private readonly Predicate<object> _canExecuteHandler;
        #endregion

        #region Constructors
        public RelayCommand(Action<object> execute) : this(execute, null)
        {
        
        }
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("Execute cannot be 'null'!");
            _executeHandler = execute;
            _canExecuteHandler = canExecute;
        }
        #endregion

        #region public Methods
        public void Execute(object parameter)
        {
            _executeHandler(parameter);
        }
        public bool CanExecute(object parameter)
        {
            if (_canExecuteHandler == null) return true;
            return _canExecuteHandler(parameter);
        }
        #endregion

        #region Events
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        #endregion

    }

In your Power class, you can add a Binding property as follows:

public class Power
{

    ICommand increaseValueCommand;
    int value = 0;

    /// <summary>
    /// Command to increase value
    /// </summary>
    public ICommand IncreaseValueCommand
    {
        get
        {
            return increaseValueCommand?? (increaseValueCommand= new RelayCommand(command => increaseValue()));
        }
    }

    public void increaseValue()
    {
        value++;
    }
}

In your xaml you then should be able to bind the button command to your ICommand interface:

<Button x:Name="Increase" Content="Increase" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Command={Binding IncreaseValueCommand}>

Keep in mind, that while this binds the Button command to your ICommand Interface, which subsequently will execute your increaseValue() Method, if you want to bind value (which I change to be a private property of the Power class) to the Progressbar, you will have to implement the INotifyPropertyChanged Interface. How this is done, is also shown in my MVVM example in the repo linked in the commments above.

Roland Deschain
  • 2,211
  • 19
  • 50
  • Again, I wrote this from scratch without being able to test, so be aware of typos or other mistakes. However, I think it shows the general gist of things :) – Roland Deschain Jul 04 '21 at 15:21
  • Wow this thing is much much easier using code. For a small application this kind of coding really an overkill. I would rather modify the classes than to go for MVVM. But thanks I will come back to this answer when(or if) I learn more about the concept. – GNZ Jul 04 '21 at 15:23
  • That is very true. However, at a certain size things are much easier to maintain with MVVM. Also, once you have done the setup once, it's basically just a matter of copy-paste (or using a MVVM library) – Roland Deschain Jul 04 '21 at 15:25
  • Yes but developing small application for control is just part of my job. So I will never work in such big projects. If it was easy I would spend time but difficult. – GNZ Jul 04 '21 at 15:26