为什么我不能在Rectangle.Width上使用IMultiValueConverter?

时间:2015-05-15 14:52:49

标签: wpf mvvm converter ivalueconverter

我需要将ItemsControl中的矩形绘制为根据绑定集合中定义的值和集合的最大值计算的宽度。所以我想我需要使用MultiValueConverter来传递项目的值和集合的最大值。

向转换器添加属性的此解决方案here可以很好地工作,但是当我将视图与VM分开时则不行。

看起来我无法通过MultiBinding设置width属性 - 我的转换器被调用并返回正确的值,但我看不到矩形:

<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?

2 个答案:

答案 0 :(得分:1)

将转换器更改为return double可以提供我想要的内容:

enter image description here

答案 1 :(得分:0)

是。这就是为什么它不起作用。

问题是在渲染Rectangle之后会评估绑定。评估后,TextBlock将删除所有内容元素。我相信TextBlocks认为字符串是一个“特殊情况”并直接渲染它们而不是创建子元素来容纳文本。因此,如果绑定的结果是字符串,则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>

这显示了三个可能的选项 - 静态文本,一次评估的绑定,以及按下按钮时更新的绑定。

这是VM:

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!";
    }
}

(为了节省空间,VM充当ICommand)我们有一个可以更新的文本属性,而不能更新。现在让我们看看他们如何在UI中呈现

The UI as shown in the window

注意,我不需要执行可更新属性 - 绑定设置的两个属性都没有矩形。在这里,让我们使用Snoop检查可视树,看看矩形是否仍在那里:

What Snoop reports

请注意,只有第一个TextBlock包含Rectangle。接下来的两个已经通过Binding的动作删除了内容。

所以,是的,你可以在矩形的宽度上使用MultiBinding,但你不能这样做。此外,在TextBlocks中抛出矩形是一种代码味道。

解决方案是使用父容器组合TextBlocks和Rectangle,而不是尝试将TextBlock用作容器本身。