新年快乐。
这是我的问题,以某种样式创建的绑定是否超出了范围。
让我解释一下,我有一个文本块,该文本块具有对“名称”列表和视图模型中的字符串列表中两个元素的值的多重绑定。
我在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>
请注意这是一个模板。
答案 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();
}