【问题标题】:Why can't I use IMultiValueConverter on Rectangle.Width?为什么我不能在 Rectangle.Width 上使用 IMultiValueConverter?
【发布时间】:2015-07-27 13:28:49
【问题描述】:

我需要在 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 吗?

【问题讨论】:

    标签: wpf mvvm converter ivalueconverter


    【解决方案1】:

    将转换器更改为返回 double 可以满足我的需求:

    【讨论】:

      【解决方案2】:

      是的。这就是它不起作用的原因。

      问题是您的绑定是在 Rectangle 呈现后评估的。评估后,TextBlock 将删除所有内容元素。我相信 TextBlocks 将字符串视为“特殊情况”并直接渲染它们,而不是创建子元素来容纳文本。因此,由于绑定的结果是字符串,因此 Rectangle 将从可视化树中移除。

      这是我在一分钟内拼凑起来的一个简短的复制品来说明。首先,用户界面:

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

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2010-11-14
        • 2011-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-15
        • 2010-11-17
        • 1970-01-01
        相关资源
        最近更新 更多