WPF中视图之间如何同步2个属性?

问题描述 投票:0回答:1

我是C#编程新手,希望对我的问题有一些见解。

我有一个标准视图,其中包含一个导航菜单,通过点击导航按钮,它将在标准视图中显示另一个视图。我的问题是,我需要将导航按钮与视图中的一些按钮 "同步",以便当其中一个按钮被关注时,两个按钮都被关注。

picture 1

picture 2

我正在使用MVVM与caliburn.micro,但我不知道如何从视图中的viewmodels中访问控件,就像你可以从后面的代码中访问一样......我想我需要用一个布尔值来设置聚焦属性,使两个按钮都被链接起来,但我不知道如何做。

c# wpf-controls
1个回答
1
投票

使用MVVM,你不想从viewModels中访问控件,因为这将违背MVVM试图从视图中解耦viewmodels的观点.如果你要使用访问viewmodel中的控件,那么你将无法在不改变viewmodel的情况下改变视图。

当你想从你的视图中传输信息到你的viewModel时,你可以使用Binding.这里的一种可能性是在你的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;
        }
    }
}

多重绑定(源码:https:/stackover) https:/stackoverflow.coma5144263413448212。 )

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 "来设置它,但我相信你必须使用元素的名称来设置焦点,所以你必须调整每个按钮的样式,通过名称来引用其他按钮。

让我知道这对你来说是否可以,这是我的第一篇文章,所以我可能已经忘记了一些事情。

© www.soinside.com 2019 - 2024. All rights reserved.