为什么我不能在 Rectangle.Width 上使用 IMultiValueConverter?
Why can't I use IMultiValueConverter on Rectangle.Width?
我需要在 ItemsControl 中绘制矩形,宽度根据绑定集合中定义的值和集合的最大值计算得出。所以我想我需要使用 MultiValueConverter 来传递项目的值和集合的最大值。
这个向转换器添加 属性 的解决方案 here 效果很好,但当我将视图与 VM 分开时就不行了。
虽然我无法使用 MultiBinding 设置宽度 属性 - 我的转换器被调用并返回正确的值,但我看不到矩形:
<ListBox x:Name="list" ItemsSource="{Binding Companies}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding CountInvitations}" />
<Rectangle Height="20" Fill="Black">
<Rectangle.Width>
<MultiBinding Converter="{StaticResource myMultiValueConverter}">
<Binding Path="CountInvitations" />
<Binding ElementName="MainLayout" Path="DataContext.MaxCount" />
</MultiBinding>
</Rectangle.Width>
</Rectangle>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
这是转换器:
int CellWidth = 200;
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int count = int.Parse(values[0].ToString());
int maxCount = int.Parse(values[1].ToString());
var width = CellWidth / maxCount * count;
return width;
}
难道不能通过 MultiBinding 设置 Rectangle.Width 吗?
是的。这就是它不起作用的原因。
问题是您的绑定是在呈现矩形之后计算的。评估后,TextBlock 会删除所有内容元素。我相信 TextBlocks 将字符串视为 "special case" 并直接呈现这些字符串,而不是创建子元素来容纳文本。因此,绑定的结果是一个字符串,Rectangle 将从可视化树中删除。
这是我在一分钟内拼凑起来的一个简短的复制品来说明。首先,UI:
<Window x:Class="TextBlockContent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="525" Width="525">
<UniformGrid Columns="1">
<TextBlock Text="This text is static">
<Rectangle Fill="Red"
Width="150"
Height="150" />
</TextBlock>
<TextBlock Text="{Binding ThisTextIsSetByABinding}">
<Rectangle Fill="Yellow"
Width="150"
Height="150" />
</TextBlock>
<TextBlock Text="{Binding ThisTextIsUpdatedByAButton}">
<Rectangle Fill="Green"
Width="150"
Height="150" />
</TextBlock>
<Button Content="Click to update the last TextBlock"
Command="{Binding}" />
</UniformGrid>
</Window>
这显示了三个可能的选项——静态文本、计算一次的绑定和在按下按钮时更新的绑定。
这是虚拟机:
public class ViewModel : INotifyPropertyChanged, ICommand
{
// events
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler CanExecuteChanged;
// this property is set once prior to the binding being evaluated
public string ThisTextIsSetByABinding { get; set; }
private string _thisTextIsUpdatedByAButton =
"This text is updated by a button";
// this one is updated and so is INPC
public string ThisTextIsUpdatedByAButton
{
get
{
return _thisTextIsUpdatedByAButton;
}
set
{
_thisTextIsUpdatedByAButton = value;
PropertyChanged(this, new
PropertyChangedEventArgs("ThisTextIsUpdatedByAButton"));
}
}
public ViewModel()
{
ThisTextIsSetByABinding = "This text is set by a binding";
}
// ICommand impl
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
ThisTextIsUpdatedByAButton = "Text updated!";
}
}
(为了保存 space,VM 充当 ICommand)我们有一个文本 属性 可以更新,一个不能。现在让我们看看它们如何在 UI
中呈现
请注意,我不需要执行可更新 属性-- 绑定设置的两个属性都没有矩形。在这里,让我们使用 Snoop 检查可视化树,看看矩形是否仍然存在:
请注意,只有第一个 TextBlock 包含 Rectangle。接下来的两个已经通过绑定操作删除了内容。
所以,是的,您可以在矩形的宽度上使用 MultiBinding,但您不能这样做。此外,在您的 TextBlock 中添加矩形有点代码味道。
解决方案是使用父容器组合 TextBlock 和 Rectangle,而不是尝试将 TextBlock 本身用作容器。
将转换器更改为 return double 给了我想要的东西:
我需要在 ItemsControl 中绘制矩形,宽度根据绑定集合中定义的值和集合的最大值计算得出。所以我想我需要使用 MultiValueConverter 来传递项目的值和集合的最大值。
这个向转换器添加 属性 的解决方案 here 效果很好,但当我将视图与 VM 分开时就不行了。
虽然我无法使用 MultiBinding 设置宽度 属性 - 我的转换器被调用并返回正确的值,但我看不到矩形:
<ListBox x:Name="list" ItemsSource="{Binding Companies}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding CountInvitations}" />
<Rectangle Height="20" Fill="Black">
<Rectangle.Width>
<MultiBinding Converter="{StaticResource myMultiValueConverter}">
<Binding Path="CountInvitations" />
<Binding ElementName="MainLayout" Path="DataContext.MaxCount" />
</MultiBinding>
</Rectangle.Width>
</Rectangle>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
这是转换器:
int CellWidth = 200;
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int count = int.Parse(values[0].ToString());
int maxCount = int.Parse(values[1].ToString());
var width = CellWidth / maxCount * count;
return width;
}
难道不能通过 MultiBinding 设置 Rectangle.Width 吗?
是的。这就是它不起作用的原因。
问题是您的绑定是在呈现矩形之后计算的。评估后,TextBlock 会删除所有内容元素。我相信 TextBlocks 将字符串视为 "special case" 并直接呈现这些字符串,而不是创建子元素来容纳文本。因此,绑定的结果是一个字符串,Rectangle 将从可视化树中删除。
这是我在一分钟内拼凑起来的一个简短的复制品来说明。首先,UI:
<Window x:Class="TextBlockContent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="525" Width="525">
<UniformGrid Columns="1">
<TextBlock Text="This text is static">
<Rectangle Fill="Red"
Width="150"
Height="150" />
</TextBlock>
<TextBlock Text="{Binding ThisTextIsSetByABinding}">
<Rectangle Fill="Yellow"
Width="150"
Height="150" />
</TextBlock>
<TextBlock Text="{Binding ThisTextIsUpdatedByAButton}">
<Rectangle Fill="Green"
Width="150"
Height="150" />
</TextBlock>
<Button Content="Click to update the last TextBlock"
Command="{Binding}" />
</UniformGrid>
</Window>
这显示了三个可能的选项——静态文本、计算一次的绑定和在按下按钮时更新的绑定。
这是虚拟机:
public class ViewModel : INotifyPropertyChanged, ICommand
{
// events
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler CanExecuteChanged;
// this property is set once prior to the binding being evaluated
public string ThisTextIsSetByABinding { get; set; }
private string _thisTextIsUpdatedByAButton =
"This text is updated by a button";
// this one is updated and so is INPC
public string ThisTextIsUpdatedByAButton
{
get
{
return _thisTextIsUpdatedByAButton;
}
set
{
_thisTextIsUpdatedByAButton = value;
PropertyChanged(this, new
PropertyChangedEventArgs("ThisTextIsUpdatedByAButton"));
}
}
public ViewModel()
{
ThisTextIsSetByABinding = "This text is set by a binding";
}
// ICommand impl
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
ThisTextIsUpdatedByAButton = "Text updated!";
}
}
(为了保存 space,VM 充当 ICommand)我们有一个文本 属性 可以更新,一个不能。现在让我们看看它们如何在 UI
中呈现请注意,我不需要执行可更新 属性-- 绑定设置的两个属性都没有矩形。在这里,让我们使用 Snoop 检查可视化树,看看矩形是否仍然存在:
请注意,只有第一个 TextBlock 包含 Rectangle。接下来的两个已经通过绑定操作删除了内容。
所以,是的,您可以在矩形的宽度上使用 MultiBinding,但您不能这样做。此外,在您的 TextBlock 中添加矩形有点代码味道。
解决方案是使用父容器组合 TextBlock 和 Rectangle,而不是尝试将 TextBlock 本身用作容器。
将转换器更改为 return double 给了我想要的东西: