使用具有多个值和值源的转换器将样式应用于用户控制

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

我在 Avalonia 工作,有一个用户控件 (UC),我想将其 IsVisible 值绑定到其 DataContext 和父控件的属性。 我有这个 UC 的一个实例,它既绑定到父 DataContext 的属性,又作为 WrapPanel 模板化 ItemsControl 的 DataTemplate,绑定到集合中每个元素的属性。 另外,还有两个这样的 ItemsControl。 “单个”实例按需要工作,当其属性为 false 并且父属性为 true 时隐藏:

        <TabControl>
          <TabItem>
            <Grid>
              <Grid.ColumnDefinitions>...
              <views:MyUserControl DataContext="{Binding ParentVMUCMember}" Width="215" Height="200" VerticalAlignment="Top">
                <views:MyUserControl.IsVisible>
                  <MultiBinding Converter="{StaticResource OrGateConverter}">
                    <Binding Path="!$parent[TabControl].((vm:ParentVM)DataContext).AreDeactivatedUCsHidden" />
                    <Binding Path="IsActivated" />
                  </MultiBinding>
                </views:MyUserControl.IsVisible>
              </views:MyUserControl>

由于此 TabControl 中 UC 的所有实例都将采用此机制并且看起来相同,因此我想创建一个样式来应用于所有实例,其中包括 IsVisible 转换。 我需要正确的语法,因为这不起作用:

          <TabControl.Styles>
            <Style Selector="views|MyUserControl">
              <Setter Property="Width" Value="215" />
              <Setter Property="Height" Value="200" />
              <Setter Property="VerticalAlignment" Value="Top" />
              <Setter Property="IsVisible">
                <Setter.Value>
                  <MultiBinding Converter="{StaticResource OrGateConverter}">
                    <Binding Path="!$parent[TabControl].((vm:ParentVM)DataContext).AreDeactivatedUCsHidden" />
                    <Binding Path="IsActivated" />
                  </MultiBinding>
                </Setter.Value>
              </Setter>
            </Style>
          </TabControl.Styles>

它给了我错误:

AVLN2000 无法解析类型“Project.ViewModels.ParentVM”上名称为“IsActivated”的属性或方法

如果我将其更改为

<Binding Path="$self.IsActivated" />
,我会收到相同的错误,但在“类型 'Project.ViewModels.MyUserControl'”上。

TabControl 的完整 AXAML 如下,以防重要:

    <TabControl>
      <TabControl.Styles>
        <Style Selector="views|MyUserControl">
          <Setter Property="Width" Value="215" />
          <Setter Property="Height" Value="200" />
          <Setter Property="VerticalAlignment" Value="Top" />
        </Style>
      </TabControl.Styles>
      <TabItem Header="Single and one on ItemsControl">
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <views:MyUserControl DataContext="{Binding ParentVMUCMember}">
            <views:MyUserControl.IsVisible>
              <MultiBinding Converter="{StaticResource OrGateConverter}">
                <Binding Path="!$parent[TabControl].((vm:ParentVM)DataContext).AreDeactivatedUCsHidden" />
                <Binding Path="IsActivated" />
              </MultiBinding>
            </views:MyUserControl.IsVisible>
          </views:MyUserControl>
          <ItemsControl ItemsSource="{Binding ParentVMFirstCollection}">
            <ItemsControl.ItemsPanel>
              <ItemsPanelTemplate>
                <WrapPanel UseLayoutRounding="True" />
              </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
              <DataTemplate>
                <views:MyUserControl>
                  <views:MyUserControl.IsVisible>
                    <MultiBinding Converter="{StaticResource OrGateConverter}">
                      <Binding Path="!$parent[TabControl].((vm:ParentVM)DataContext).AreDeactivatedUCsHidden" />
                      <Binding Path="IsActivated" />
                    </MultiBinding>
                  </views:MyUserControl.IsVisible>
                </views:MyUserControl>
              </DataTemplate>
            </ItemsControl.ItemTemplate>
          </ItemsControl>
        </Grid>
      </TabItem>
      <TabItem Header="The second ItemsControl">
        <ItemsControl ItemsSource="{Binding ParentVMSecondCollection}">
          <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
              <WrapPanel Orientation="Horizontal" UseLayoutRounding="True" />
            </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>
          <ItemsControl.ItemTemplate>
            <DataTemplate>
              <views:MyUserControl>
                <views:MyUserControl.IsVisible>
                  <MultiBinding Converter="{StaticResource OrGateConverter}">
                    <Binding Path="!$parent[TabControl].((vm:ParentVM)DataContext).AreDeactivatedUCsHidden" />
                    <Binding Path="IsActivated" />
                  </MultiBinding>
                </views:MyUserControl.IsVisible>
              </views:MyUserControl>
            </DataTemplate>
          </ItemsControl.ItemTemplate>
        </ItemsControl>
      </TabItem>
    </TabControl>

非常感谢任何帮助...

data-binding user-controls styles converters avaloniaui
1个回答
0
投票

我在 Avalonia 工作,有一个用户控件 (UC),我想将其 IsVisible 值绑定到其 DataContext 和父控件的属性。

你不希望这样,即使你让它工作,这也是你在 MVVM 中不希望的紧密耦合。不要尝试将一个视图的属性绑定到另一个视图,父视图唯一应该做的就是创建子视图,分配它的 DataContext,并将其添加到 ContentPresenter。 子视图应该忽略父视图。

但是,视图构造子视图是可以的。 视图模型也可以为这些子视图构建子视图模型并将它们作为属性提供,并且父视图模型可以与它们交互,尽管子视图模型也应该不知道它的父视图模型。您想要的是每个视图都有自己的视图模型,并且父视图模型的视图模型将在其自己的 IsVisible 属性的设置器中设置子视图模型的 IsVisible 属性。

策略是这样的:

  1. 父视图模型创建子视图模型并通过属性使其可用(通常这是只读的,不需要通知)。
  2. 父视图创建一个子视图,将其 DataContext 绑定到步骤 1 中提到的属性(使用它自己的 DataContext)。 然后,父视图将此视图设置为它所使用的任何 ContentPresenter 的 Content 属性,例如您的选项卡项。
  3. 父视图的 IsVisible 属性绑定到其自己的视图模型中的适当属性。
  4. 子视图的 IsVisible 属性绑定到其自己的视图模型中的适当属性。
  5. 父视图模型的 IsVisible 属性设置器还使用步骤 #1 中的属性在子视图模型中设置 IsVisible 属性。
  6. 如果需要,子视图模型的 PropertyChanged 事件可以由父视图模型监视,以了解可能源自那里的 IsVisible 更改并采取相应的操作。
© www.soinside.com 2019 - 2024. All rights reserved.