窗口上兄弟控制的访问值

时间:2016-07-10 20:56:33

标签: c# wpf xaml multibinding

我在Window.Resources

中有这个
<Window.Resources>
    <ValueConverters:StudyPointWorkingOn x:Key="StudyPointWorkingOn" />

    <Style x:Key="StudyPointComboBoxStyle" TargetType="ComboBoxItem">
        <Setter Property="Tag" Value="{Binding Number}" />
        <Style.Triggers>
            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource StudyPointWorkingOn}">
                        <Binding RelativeSource="{RelativeSource Self}" Path="Tag"/>
                        <Binding Path="DataContext.SelectedStudentItem" ElementName="oclmEditor" UpdateSourceTrigger="PropertyChanged" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="Red"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>

    <DataTemplate x:Key="StudyPointComboItem">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Number}"/>
            <TextBlock Text=" - "/>
            <TextBlock Text="{Binding Title}"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>

在我的MainWindow代码中,我有几个地方使用上述资源。这是一个例子:

<StackPanel>
    <StackPanel.Style>
        <Style TargetType="{x:Type StackPanel}">
            <Setter Property="IsEnabled" Value="False"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding NumberClasses, ConverterParameter=1, Converter={StaticResource IsEqualOrGreaterThanConverter}}" Value="True">
                    <Setter Property="IsEnabled" Value="True" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </StackPanel.Style>
    <Label Content="Student:"/>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="auto"/>
        </Grid.ColumnDefinitions>
        <TextBox x:Name="textBibleReadingMain" Grid.Column="0" Margin="2" IsEnabled="False"
                Text="{Binding BibleReadingMainName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
        <Button x:Name="buttonBibleReadingMain" Grid.Column="1" Background="Transparent"
                DataContext="{Binding DataContext, ElementName=oclmEditor}"
                    Command="{Binding ApplicationCommand}" CommandParameter="BibleReadingMain">
            <Image Source="Images/AssignmentTypeBibleReading16.png" Margin="2"/>
        </Button>
    </Grid>
    <Label Content="Study:"/>

    <ComboBox DataContext="{Binding DataContext, ElementName=oclmEditor}"
              ItemsSource="{Binding ReadingStudyPointsList}"
              ItemContainerStyle="{StaticResource StudyPointComboBoxStyle}"
              ItemTemplate="{StaticResource StudyPointComboItem}"/>
</StackPanel>

我已将其纳入上下文以显示我的问题。首先,我必须指出它的工作原理。我现在遇到的问题是因为我想略微改变逻辑。

通过几个控件查看TextBox之前的ComboBox对象:

<TextBox x:Name="textBibleReadingMain" Grid.Column="0" Margin="2" IsEnabled="False"
        Text="{Binding BibleReadingMainName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>

如果可能,我想将Text值BibleReadingMainName作为MultiBinding对象中的参数传递。但它很复杂,因为我有几个地方,我有这种风格:

[Text][Button]
[Label]
[Combo]

因此,在每个实例中,[Text]元素具有不同的名称,并且关联的属性将不同。有什么方法我仍然可以使用一个资源,但以某种方式通过TextBox.Text或适当的Property?我知道我可以使用RelativeSource,但这是为了寻找祖先,这更像是一个侄子... :)

更新

谢谢你提供的答案到目前为止。请允许我向您展示我所做的工作,因为我不能完全看到如何实现这一点,因为您建议ViewModel

  1. 我调整了Windows.Resources

        

    <Style x:Key="StudyPointComboBoxStyle" TargetType="ComboBoxItem">
        <Setter Property="Tag" Value="{Binding Number}" />
        <Style.Triggers>
            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource StudyPointWorkingOn}">
                        <Binding RelativeSource="{RelativeSource Self}" Path="Tag"/>
                        <Binding Path="DataContext" ElementName="oclmEditor" UpdateSourceTrigger="PropertyChanged" />
                        <Binding Path="Tag" RelativeSource="{RelativeSource AncestorType=ComboBox}"/>
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="Red"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    
    <DataTemplate x:Key="StudyPointComboItem">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Number}"/>
            <TextBlock Text=" - "/>
            <TextBlock Text="{Binding Title}"/>
        </StackPanel>
    </DataTemplate>
    

  2. 如您所见,我现在也传递了ComboBox Tag属性。

    1. 我的各种ComboBox控件现在定义如下(其中3个显示):

    2. 如您所见,每个ComboBox将其Tag设置为ViewModel中的相应属性(随后连接到它自己的TextBox)。

      1. Converter方法现在看起来像这样:

        命名空间OCLMEditor.ValueConverters {     class StudyPointWorkingOn:IMultiValueConverter     {         public object Convert(object [] values,Type targetType,object parameter,CultureInfo culture)         {             int iStudyNumber =(int)values [0];             OCLMEditorViewModel vm =(OCLMEditorViewModel)值[1];             string strStudent =(string)values [2];

                if (vm != null && strStudent != null)
                {
                    Student oStudent = vm.FindStudent(strStudent);
                    if (oStudent != null && oStudent.IsWorkingOnStudyPoint(iStudyNumber))
                        return true;
                }
        
                return false;
            }
        
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
        

        }

      2. 最后,我必须向ViewModel添加一个公共包装器方法:

        public Student FindStudent(string strStudent) {     return _Model.FindStudent(strStudent); }

      3. 上述方法对我有用。但提供的答案是使用ViewModel来包装StudyPointItem和关联的Name属性。我无法完全看到提议的代码如何反映上述工作流程。

1 个答案:

答案 0 :(得分:2)

IMO,我会以某种方式将必要的信息传递给您绑定的每个项目,而不是查找通过控件树导航的信息。因此,我认为它更易于维护,因为如果布局发生更改,则不必更新绑定。

在您的情况下,组合框的每个项目的DataContext是ReadingStudyPointsList的每个元素。因此,当您创建传递“this”实例的元素以访问ViewModel的每个属性时,您可以传递对具有BibleReadingMainName的实际ViewModel的引用,例如:

this.ReadingStudyPointsList.Add(new ReadingStudyPointItemViewModel(this, other parameters))

那么在您的ReadingStudyPointItemViewModel中,您可以拥有一个属性,该属性包含在ctor中分配的父ViewModel以访问您需要的信息:

public ParentViewModel ParentVM { get; set; }

最后,您的绑定将变为:

<Style x:Key="StudyPointComboBoxStyle" TargetType="ComboBoxItem">
        <Setter Property="Tag" Value="{Binding Number}" />
        <Style.Triggers>
            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource StudyPointWorkingOn}">
                        <Binding RelativeSource="{RelativeSource Self}" Path="Tag"/>
                        <Binding Path="DataContext.SelectedStudentItem" ElementName="oclmEditor" UpdateSourceTrigger="PropertyChanged" />
                        <Binding Path="DataContext.ParentVM.BibleReadingMainName" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="Red"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>

我希望这适合你。