Failing To get Slider Value n ViewModel Class in WPF

Topics: Questions
Oct 18, 2012 at 7:44 AM

I am working on WPF Sliders using MVVM pattern. I have a slider, textbox and label in my xaml as follows:

<Grid Grid.Row="2">
           <Label Name="BitDelay" Content="Bit Delay" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,205,0" Height="25" Width="55" />
           <Slider Height="23" HorizontalAlignment="Center" Minimum="0.0" Maximum="255.0" TickFrequency="1.0" Margin="95,0,0,0" Name="bitdelayslider" VerticalAlignment="Center" Width="160" />
           <TextBox Name="BitDelayValue" IsReadOnly="True" Text="{Binding ElementName=bitdelayslider,Path=Value, StringFormat=0.0}" Width="40" Height="20" Margin="0,0,110,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>

This gives me slider value in my textbox whenever I move the slider. How can i create its property in viewmodel where I can bind the value of slider and retrieve the value in order to execute further code.

In C++ app I had done as follows:
void CMSP430CodecWidget::sliderValueChanged(Slider *slider)
{
	memset(sendBuf, 0, CODEC_BUFFER_SIZE);
	unsigned cmd = 0;
	int numBytes = 0;

	if(slider == m_codecBitDelaySlider)
	{
		cmd = ((CODEC_BIT_CMD & 0x7F00) | (m_slot & 0xFF));
		sendBuf[numBytes++] = (unsigned char)(m_codecBitDelaySlider->getValue());
	}

I wanna do it in my viewmodel class since I am following MVVM pattern. How can i do that? :)

Oct 18, 2012 at 7:50 AM

If you have the data context set the the view model, this should be sufficient:

<Slider Minimum="0.0" Maximum="255.0" TickFrequency="1.0" Margin="95,0,0,0" Value="{Binding MyViewModelProperty, Mode=TwoWay}" />

Oct 18, 2012 at 8:00 AM

Thanks for the quick reply :)

This is what I did in ViewModel class:

private double mBitDelayValue;
        public double BitDelayValue
        {
            get
            {
                return mBitDelayValue;
            }

            set
            {
                mBitDelayValue = value;
                OnPropertyChanged("BitDelayValue");
            }
        }

Xaml:

<Grid Grid.Row="2">
                    <Label Name="BitDelay" Content="Bit Delay" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,205,0" Height="25" Width="55" />
                    <Slider Height="23" HorizontalAlignment="Center" Value="{Binding BitDelayValue, Mode=TwoWay}" Minimum="0.0" Maximum="255.0" TickFrequency="1.0" Margin="95,0,0,0" Name="bitdelayslider" VerticalAlignment="Center" Width="160" />
                    <TextBox Name="BitDelayValue" IsReadOnly="True" Text="{Binding ElementName=bitdelayslider,Path=Value, StringFormat=0.0}" Width="40" Height="20" Margin="0,0,110,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>

But is there a way I can have something like slidervaluechanged in viewmodel where I can use this value and execute statements which use them?
I dont want to create slidervalue_changed() in xaml.cs. Is it possible to achieve it in viewmodel???
 

Oct 18, 2012 at 8:03 AM

If you use a Catel vm, you get automatic change notifications. Internally, the OnPropertyChanged you call is responsible to let the all interested objects know that the value has changed. If you want to do something, simple subscribe to INotifyPropertyChanged.PropertyChanged event which the OnPropertyChanged in the setter invokes.

Oct 18, 2012 at 8:07 AM

Since value has the slider value, I did the following and it seems to work fine. Have a look:

private double mBitDelayValue;
        public double BitDelayValue
        {
            get
            {
                return mBitDelayValue;
            }

            set
            {
                mBitDelayValue = value;
                Byte[] sendBuf = new Byte[256];                
                int cmd = 0;
                int numBytes = 0;

                cmd = ((0x9300 & 0x7F00) | (m_slot & 0xFF));
                sendBuf[numBytes++] = Convert.ToByte(value);

                if (0 != cmd)
                {
                    mCom.WriteInternalCommand(cmd, numBytes, ref sendBuf);
                }

                OnPropertyChanged("BitDelayValue");
            }
        }
I am using value and converting it to Byte and I on debugging the code I get the expected value :) Is this a right way to do?

Oct 18, 2012 at 8:11 AM

No, this is wrong. The view binds to BitDelayValue. That raises the PropertyChanged event which is all the setter should do.

When you override OnPropertyChanged, you can handle custom code:

protected override OnPropertyChanged(string propertyName)
{
    base.OnPropertyChanged(propertyName);

    if (string.Equals("BitDelayValue", propertyName))
    {
               mBitDelayValue = value;
                Byte[] sendBuf = new Byte[256];                
                int cmd = 0;
                int numBytes = 0;

                cmd = ((0x9300 & 0x7F00) | (m_slot & 0xFF));
                sendBuf[numBytes++] = Convert.ToByte(value);

                if (0 != cmd)
                {
                    mCom.WriteInternalCommand(cmd, numBytes, ref sendBuf);
                }
    }

}

Oct 18, 2012 at 8:24 AM
Edited Oct 18, 2012 at 8:27 AM

So you mean to say I need to do something like dis:

 

private double mBitDelayValue;
        public double BitDelayValue
        {
            get
            {
                return mBitDelayValue;
            }

            set
            {
                mBitDelayValue = value;
                OnPropertyChanged("BitDelayValue");
            }
        }

 

and then put this method:

 

protected override OnPropertyChanged(string propertyName)
{
    base.OnPropertyChanged(propertyName);

    if (string.Equals("BitDelayValue", propertyName))
    {
               mBitDelayValue = value;
                Byte[] sendBuf = new Byte[256];                
                int cmd = 0;
                int numBytes = 0;

                cmd = ((0x9300 & 0x7F00) | (m_slot & 0xFF));
                sendBuf[numBytes++] = Convert.ToByte(value);

                if (0 != cmd)
                {
                    mCom.WriteInternalCommand(cmd, numBytes, ref sendBuf);
                }
    }

}
#region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion

When I did this, all OnPropertyChanged() are throwing error. since it leads to ambiguity. Damn I am confused!!! How can I solve it?

Oct 18, 2012 at 8:28 AM

You don't have a ViewModelBase with OnPropertyChanged. You cannot override a method that you define on the same class. I really recommend you start using Catel, or if you don't want to do that, place such basic questions on the MSDN forums.

Oct 18, 2012 at 8:29 AM

Well I will start using Catel now :) Thanks for being patient GeertvanHorrik )