panjo
panjo

Reputation: 3515

accessing to panel (view) object from the viewmodel

I just finished with watching practical mvvm presentation video on youtube and if I understand correctly moving logic from codebehing to view model is good practice and we should strive to this pattern.

Having this in mind I have one simple question. Inside xaml I have four radio buttons

<StackPanel x:Name="panel">
    <RadioButton GroupName="myGroup" Name="Option1" Content="option one" IsChecked="True"  Width="40"/>
     <RadioButton GroupName="myGroup" Name="Option2" Content="option two" IsChecked="False" Width="80"/>
     <RadioButton GroupName="myGroup" Name="Option3" Content="option three" IsChecked="False" Width="60"/>
</StackPanel>

I want to use this code inside viewmodel below to fetch selected radio btn.

var checkedValue = panel.Children.OfType<RadioButton>()
                 .FirstOrDefault(r => r.IsChecked.HasValue && r.IsChecked.Value);

Question is: How can I access to this panel object from the viewmodel? It's not data to use binding.

Update: as @Rohit Vatss said "View objects should not be accessed from ViewModel" I would change question to How to know which radio button is selected using viewmodel?

Upvotes: 0

Views: 206

Answers (2)

dkozl
dkozl

Reputation: 33364

You can do it by creating one property in you ViewModel, lets say GroupIndex

private int _groupIndex = 1;

public int GroupIndex
{
   get { return _groupIndex; }
   set
   {
      if (_groupIndex == value) return;
      _groupIndex = value;
      OnPropertyChanged("GroupIndex");
   }
}

then create simple converter which will convert current GroupIndex value to true or false and back:

public class IndexBooleanConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
     if (value == null || parameter == null)
        return false;
     else
        return (int)value == System.Convert.ToInt32(parameter);
  }

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
     if (value == null || parameter == null)
         return null;
     else if ((bool)value)
         return System.Convert.ToInt32(parameter);
     else
         return DependencyProperty.UnsetValue;
  }
}   

and then bind your RadioButton to GroupIndex which will will be set to 1, 2 or 3 depending on which RadioButton is checked

<StackPanel>
  <StackPanel.Resources>
      <local:IndexBooleanConverter x:Key="IndexBooleanConverter"/>
  </StackPanel.Resources>
  <RadioButton Content="Option1" IsChecked="{Binding Path=GroupIndex, Converter={StaticResource IndexBooleanConverter}, ConverterParameter=1}"/>
  <RadioButton Content="Option2" IsChecked="{Binding Path=GroupIndex, Converter={StaticResource IndexBooleanConverter}, ConverterParameter=2}"/>
  <RadioButton Content="Option3" IsChecked="{Binding Path=GroupIndex, Converter={StaticResource IndexBooleanConverter}, ConverterParameter=3}"/>
</StackPanel>

In this case GroupIndex is int but you can also use same logic if for example your GroupIndex is an enum

Upvotes: 1

Jero Franzani
Jero Franzani

Reputation: 473

Well an aprroach would be for example using a Command and a Command Parameter on the radiobuttons Binded to your viewmodel. For example:

<RadioButton GroupName="myGroup" Name="Option1" Content="option one" IsChecked="True"  Width="40" Command="{Binding RbCheckedCommand}" CommandParameter="RB1"/>
     <RadioButton GroupName="myGroup" Name="Option2" Content="option two" IsChecked="False" Width="80" Command="{Binding RbCheckedCommand}" CommandParameter="RB2"/>
     <RadioButton GroupName="myGroup" Name="Option3" Content="option three" IsChecked="False" Width="60" Command="{Binding RbCheckedCommand}" CommandParameter="RB3"/>

Then on your ViewModel:

private readonly DelegateCommand<object> rbCheckedCommand;

public ICommand RbCheckedCommand
{
    get { return this.rbCheckedCommand; }
}


private void RbCheckedCommandExecute(object obj)
{
    string rbselected = obj.ToString();
}

And on the constructor of the class:

this.rbCheckedCommand = new DelegateCommand<object>(RbCheckedCommandExecute);

You will have to use the prism adding:

using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;

And making your class inherits from NotificationObject so you can use the Property changed easily.

Hope it helps.

Upvotes: 0

Related Questions