样式触发的绑定永远不会释放

时间:2019-01-10 17:21:44

标签: c# .net binding datatrigger

新年快乐。

这是我的问题,以某种样式创建的绑定是否超出了范围。

让我解释一下,我有一个文本块,该文本块具有对“名称”列表和视图模型中的字符串列表中两个元素的值的多重绑定。

我在xaml中使用魔术字符串逐个索引地添加这些元素(喜欢,我知道,我不知道该怎么做,如果我在集合上设置绑定,则itemChanged事件不会触发绑定...)

我需要更改值,并且我真的不想创建任何类型的访问器。我希望在视图中全部处理。

<TextBlock>
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Setter Property="Text"
                        Value="" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=IsGroupedBy, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource  Mode=FindAncestor, AncestorType=Window}}"
                                 Value="True">
                        <Setter Property="Text">
                            <Setter.Value>
                                <MultiBinding Converter="{StaticResource ConcatStringConvertor}"
                                              UpdateSourceTrigger="PropertyChanged"
                                              Mode="OneWay">
                                    <Binding Path="Names[1]"
                                             RelativeSource="{RelativeSource  Mode=FindAncestor, AncestorType=Window}"
                                             UpdateSourceTrigger="PropertyChanged" />
                                    <Binding Path="Names[2]"
                                             RelativeSource="{RelativeSource  Mode=FindAncestor, AncestorType=Window}"
                                             UpdateSourceTrigger="PropertyChanged" />
                                </MultiBinding>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=IsGroupedBy, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource  Mode=FindAncestor, AncestorType=Window}}"
                                 Value="False">
                        <Setter Property="Text" Value="0">
                        </Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>

我使用“ IsGroupedBy == true”上的数据触发器以一种样式设置了此绑定。 如果“ IsGroupedBy == false”,则文本框文本设置为0。 它确实起作用(当useBinding为true时,我将两个值连接在文本块中,否则为“ 0”。

我的问题现在出现了,我第一次将useBinding设置为true时,创建了绑定。从现在开始,如果我更改(通常为空)列表,即使将IsGroupedBy设置为FALSE,也将对绑定进行评估;

然后,我在Index超出范围时导致参数异常。 (这是沉默的,最终用户永远不会知道,但是它并不是真正的干净和注重性能……)

System.Windows.Data Warning: 17 : Cannot get 'Item[]' value (type 'String') from 'Names' (type 'ObservableCollection`1'). BindingExpression:Path=Names[1]; DataItem='MainWindow' (Name=''); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: ...

我认为条件绑定将解决此问题,但不会...

我对任何解决方案都开放(特别是如果我能找到从绑定中删除那些Names [1]的方法的话)

PS:对不起,我的英语。

EDIT :
    public ObservableCollection<string> Names { get; set; }

编辑2: 我尝试了另一种方法,我像这样使用优先级绑定:

<TextBlock.Text>
                <PriorityBinding>
                    <Binding Path="IsGroupedBy"
                             Converter="{StaticResource NotFalseToUnsetValueConverter}"
                             UpdateSourceTrigger="PropertyChanged"
                             RelativeSource="{RelativeSource  Mode=FindAncestor, AncestorType=Window}" />
                    <Binding Path="Names[1]"
                             UpdateSourceTrigger="PropertyChanged"
                             RelativeSource="{RelativeSource  Mode=FindAncestor, AncestorType=Window}" />
                </PriorityBinding>
            </TextBlock.Text>


public class NotFalseToUnsetValueConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var groupBy = value as bool?;
            return (groupBy.Value == true)
                ? DependencyProperty.UnsetValue // evaluate next binding which is on array
                : "dont bind array"; // stop at first binding and dont check array  
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
    }

但是我遇到了同样的问题,我第一次评估Names [1]上的绑定时,就以某种方式在某处注册了

即使我不再绑定到第二个绑定,列表上的任何清空也会发送错误:

System.Windows.Data Warning: 17 : Cannot get 'Item[]' value (type 'String') from 'Names' (type 'ObservableCollection`1'). BindingExpression:Path=Names[1]; DataItem='MainWindow' (Name=''); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException

编辑3: 这是真正的绑定:

<DataTemplate x:Key="customGroupValueTemplate">
            <Grid Width="{Binding ElementName=uxGrid, Path=ActualWidth}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="60" />
                </Grid.ColumnDefinitions>
                <dxe:CheckEdit  Grid.Column="0"
                                Initialized="cbGroupSummary_Initialized"
                                Checked="cbGroupSummary_Checked"
                                Unchecked="cbGroupSummary_Unchecked"
                                Content="{Binding Value}" />
                <TextBlock Grid.Column="2"
                           Margin="10,0,0,0"
                           VerticalAlignment="Center"
                           Text="{Binding Path=(dxg:RowData.RowData).GroupSummaryData[0].Text, RelativeSource={RelativeSource TemplatedParent}}" />
                <TextBlock  Grid.Column="4"
                            Margin="10,0,0,0"
                            HorizontalAlignment="Right"
                            VerticalAlignment="Center">
                    <TextBlock.Text>
                        <MultiBinding Converter="{StaticResource GetPercentAsTextConv}"
                                      UpdateSourceTrigger="PropertyChanged"
                                      Mode="OneWay">
                            <Binding Path="(dxg:RowData.RowData).GroupSummaryData[1].Value"
                                     RelativeSource="{RelativeSource Self}"
                                     UpdateSourceTrigger="PropertyChanged" />
                            <Binding Path="(dxg:RowData.RowData).GroupSummaryData[2].Value"
                                     RelativeSource="{RelativeSource Self}"
                                     UpdateSourceTrigger="PropertyChanged" />
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>
                <ProgressBar  Grid.Column="5"
                              Width="100"
                              Height="10"
                              Margin="10 0 0 0"
                              HorizontalAlignment="Right"
                              VerticalAlignment="Center">
                    <ProgressBar.Value>
                        <MultiBinding Converter="{StaticResource GetPercentConv}"
                                      UpdateSourceTrigger="PropertyChanged"
                                      Mode="OneWay">
                            <Binding Path="(dxg:RowData.RowData).GroupSummaryData[1].Value"
                                     RelativeSource="{RelativeSource TemplatedParent}"
                                     UpdateSourceTrigger="PropertyChanged" />
                            <Binding Path="(dxg:RowData.RowData).GroupSummaryData[2].Value"
                                     RelativeSource="{RelativeSource TemplatedParent}"
                                     UpdateSourceTrigger="PropertyChanged" />
                        </MultiBinding>
                    </ProgressBar.Value>
                </ProgressBar>
            </Grid>
        </DataTemplate>

请注意这是一个模板。

2 个答案:

答案 0 :(得分:0)

我认为您的意思是IsGroupedBy而不是useBinding。 不太好的解决方案,但您可以将Binding Path="Names[1]"替换为Binding Path="Names.ElementAtOrDefault(1)"

答案 1 :(得分:0)

为什么要使用多重绑定?

<TextBlock>
    <TextBlock.Style>
        <Style TargetType="TextBlock">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=IsGroupedBy, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource  Mode=FindAncestor, AncestorType=Window}}"}" Value="True">
                    <Setter Property="Text" Value="{Binding Path=Names, Converter={StaticResource FirstTwoListValuesElemToStringConverter}}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=IsGroupedBy, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource  Mode=FindAncestor, AncestorType=Window}}"}" Value="False">
                    <Setter Property="Text" Value="0"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBlock.Style>
</TextBlock>

以及转换器

[ValueConversion(typeof(ObservableCollection<string>), typeof(string))]
class FirstTwoListValuesElemToStringConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        System.Collections.ObjectModel.ObservableCollection<string> names = ((System.Collections.ObjectModel.ObservableCollection<string>)value);
        if ((names != null) && (names.Count > 2))
            return names.FirstOrDefault() + names.ElementAtOrDefault(1);
        else
            return System.Windows.DependencyProperty.UnsetValue;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}