Как синхронизировать 2 свойства между представлениями в WPF? - PullRequest
0 голосов
/ 02 апреля 2020

Я новичок в C# программировании и ищу понимание своей проблемы.

У меня есть стандартный вид, который содержит навигационное меню, и при нажатии кнопок навигации он отображает другой вид в рамках стандарта. Посмотреть. Моя проблема в том, что мне нужно «синхронизировать» кнопки навигации с некоторыми кнопками в представлении, чтобы обе кнопки были сфокусированы, когда одна из них есть. см. рисунки ниже.

picture 1

picture 2

Я использую MVVM с caliburn.micro, но не могу понять, как получить доступ к элементам управления из просматривать в моделях представления, как вы можете из кода позади .. Я думаю, мне нужно установить свойство focus с логическим значением, с которым связаны обе кнопки, но я не знаю, как.

1 Ответ

1 голос
/ 01 мая 2020

Используя 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". Но я полагаю, что вам придется использовать имя элемента для установки фокуса, чтобы вам пришлось адаптировать стиль для каждой кнопки, чтобы ссылаться на другую кнопку по имени.

Дайте мне знать, если это нормально для вас это мой первый пост, поэтому я мог кое-что забыть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...