Используя MVVM, вы не хотите получать доступ к элементам управления из viewModels, потому что это будет go против точки MVVM, пытающейся отделить модели представления от представления. Если бы вы использовали доступ к элементам управления в вашей модели представления, то вы не смогли бы изменить представление без изменения модели представления.
Когда вы хотите передать информацию из вашего представления в вашу модель представления, вы можете использовать Привязка В данном случае возможно иметь информацию о представлении с фокусом в вашей viewModel и заставить представление реагировать на изменение:
В вашей viewModel:
public class MainWindowViewModel : INotifyPropertyChanged
{
/// <summary>
/// The list of views (the enum doesn't have to be in the viewModel, it can be anywhere)
/// </summary>
public enum Views
{
View1,
View2,
View3
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyChange(PropertyChangedEventArgs e)
{
PropertyChanged?.Invoke(this, e);
}
private Views focusedView;
/// <summary>
/// View with the focus
/// </summary>
public Views FocusedView
{
get
{
return this.focusedView;
}
set
{
this.focusedView = value;
NotifyChange(new PropertyChangedEventArgs("FocusedView"));
}
}
/// <summary>
/// Constructor
/// </summary>
public MainWindowViewModel()
{
this.FocusedView = Views.View1;
}
}
MainWindow.xaml :
<Window.Resources>
<local:MultiValueEqualityConverter x:Key="MultiValueEqualityConverter" />
<Style x:Key="focusedButtonStyle" TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="Gray"/>
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<!--It is not possible to make a datatrigger with a Binding in the value Property
so the MultiBinding is a neat trick to avoid having to adapt the style for each Button-->
<MultiBinding Converter="{StaticResource MultiValueEqualityConverter}">
<Binding RelativeSource="{RelativeSource Self}"
Path="Tag" Mode="OneWay"/>
<Binding RelativeSource="{RelativeSource Self}"
Path="DataContext.FocusedView" Mode="OneWay"
UpdateSourceTrigger="PropertyChanged" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="2" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" Grid.Column="0">
<Button Margin="5" Content="View1" GotFocus="Button_GotFocus"
Tag="{x:Static local:MainWindowViewModel+Views.View1}"
Style="{StaticResource focusedButtonStyle}">
</Button>
<Button Margin="5" Content="View2" GotFocus="Button_GotFocus"
Tag="{x:Static local:MainWindowViewModel+Views.View2}"
Style="{StaticResource focusedButtonStyle}" />
<Button Margin="5" Content="View3" GotFocus="Button_GotFocus"
Tag="{x:Static local:MainWindowViewModel+Views.View3}"
Style="{StaticResource focusedButtonStyle}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="1" MaxHeight="30" VerticalAlignment="Top" >
<Button Margin="5" Content="View1" GotFocus="Button_GotFocus"
Tag="{x:Static local:MainWindowViewModel+Views.View1}"
Style="{StaticResource focusedButtonStyle}" />
<Button Margin="5" Content="View2" GotFocus="Button_GotFocus"
Tag="{x:Static local:MainWindowViewModel+Views.View2}" Style="{StaticResource focusedButtonStyle}"/>
<Button Margin="5" Content="View3" GotFocus="Button_GotFocus"
Tag="{x:Static local:MainWindowViewModel+Views.View3}" Style="{StaticResource focusedButtonStyle}" />
</StackPanel>
</Grid>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
private void Button_GotFocus(object sender, RoutedEventArgs e)
{
if( sender is Button button && this.DataContext is MainWindowViewModel vm)
{
//The information is stored in the tag in order to avoid aving to do as switch or if statement
vm.FocusedView = (MainWindowViewModel.Views)button.Tag;
}
}
}
MultiBinding (источник: { ссылка })
public class MultiValueEqualityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values?.All(o => o?.Equals(values[0]) == true) == true || values?.All(o => o == null) == true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Результат здесь:
Вы заметите, что я фактически не изменяю свойство кнопок IsFocused, вы можете установить его, используя Property = "FocusManager.FocusedElement". Но я полагаю, что вам придется использовать имя элемента для установки фокуса, чтобы вам пришлось адаптировать стиль для каждой кнопки, чтобы ссылаться на другую кнопку по имени.
Дайте мне знать, если это нормально для вас это мой первый пост, поэтому я мог кое-что забыть.