【问题标题】:Why is data binding to canvas not updating UI为什么数据绑定到画布不更新 UI
【发布时间】:2019-07-08 10:18:04
【问题描述】:

我正在尝试对一组行进行数据绑定,并对它们执行排序功能,并在排序完成后更新 UI(希望显示排序算法的差异)。

我有一个基本的 WPF 应用程序,它由一个绑定到对象集合的 ItemsControl 组成。这些对象在第一次渲染屏幕的时候是正确绑定的,但是排序操作完成后,底层列表已经正确排序了,但是UI没有重绘?

这是我的 XAML

<Grid>
   <Button Content="Sort" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="12" MinWidth="80" Click="Button_Click"/>
    <ItemsControl x:Name="mainControl" ItemsSource="{Binding Values}" ItemTemplate="{StaticResource LineDataTemplate}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter" />
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</Grid>

有一个xaml数据模板

<DataTemplate x:Key="LineDataTemplate">
    <Line X1="{Binding X1}" Y1="{Binding Y1}"
          X2="{Binding X2}" Y2="{Binding Y2}"
          Stroke="DarkGray" StrokeThickness="3"/>
</DataTemplate>

主数据上下文包含此 Line 对象的列表

public class Line
{
    public int X1 { get; set; }

    public int Y1 { get; set; }

    public int X2 { get; set; }

    public int Y2 { get; set; }
}

当初始化数据上下文时,我会创建一些随机行

private void RandomiseLines()
{
    var rnd = new Random();
    var startingPoint = 2;

    Values = new List<Line>();

    for (int i = 0; i < 3; i++)
    {
        Values.Add(new Line() { X1 = startingPoint, Y1 = 420, X2 = startingPoint, Y2 = (420 - rnd.Next(1, 300)) });
        startingPoint += 4;
    }
}

然后我在 UI 上有一个按钮,它调用并(现在)使用 linq 调用基本排序

Values = Values.OrderBy(x => x.Y2).ToList();

保存此列表的数据上下文实现了 INotifiedProperty 已更改接口,一旦对列表进行排序,我就会调用 Property changed 事件。尽管底层列表已排序,但 UI 似乎没有重绘,但我尝试使用 ObservableCollection 并包装在 Dispatcher 中,但似乎没有引发任何绑定错误或异常。谁能解释一下为什么没有更新?

编辑:添加预期结果 预期的结果将是 ItemsControl 重绘本身,并且行将采用新的排序顺序

【问题讨论】:

  • 排序的预期效果是什么?不是所有的线条都在画布中绘制吗?空的 ItemContainerStyle 的用途是什么?
  • 你是否为 Values 属性实现了 INotifyPropertyChanged? IE。它的 setter 会触发 PropertyChanged 事件吗?
  • 谢谢,我已经更新了原始问题,但本质上我希望这些线条按顺序重新绘制。 DataContext 还实现了 NotifyPropertyChanged 接口。再次感谢
  • 使用 ObservableCollection 代替 List
  • Values setter 会触发 PropertyChanged 事件吗? “排序顺序”是指画布中的堆叠(即 z)顺序?

标签: c# wpf data-binding


【解决方案1】:

您最好使用Rectangle 而不是Line,因为它不依赖坐标进行定位。你只需给他们一个共享的Width,但给他们一个变量HightItemsPanel 应该是 StackPanelStackPanel.Orientation 设置为 Horizontal。值集合必须是 ObservableCollection&lt;double&gt;。然后它应该按预期运行。
这样,条形的顺序将反映集合的顺序。

主视图

<StackPanel>
  <Button Content="Sort"
          Click="Button_Click" />
  <ItemsControl x:Name="mainControl"
                ItemsSource="{Binding Values}"
                ItemTemplate="{DynamicResource LineDataTemplate}">
    <ItemsControl.Resources>
      <DataTemplate x:Key="LineDataTemplate" DataType="system:Double">
        <Rectangle Width="5" 
                   Height="{Binding}" 
                   VerticalAlignment="Bottom"
                   Fill="DarkGray"
                   Margin="0,0,3,0" />
      </DataTemplate>
    </ItemsControl.Resources>

    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</StackPanel>

Button.Click 事件处理程序

private void Button_Click(object sender, RoutedEventArgs e)
{
  var viewModel = this.DataContext as TestViewModel;
  var orderedValues = viewModel.Values.OrderBy(value => value).ToList();
  viewModel.Values = new ObservableCollection<double>(orderedValues);
}

视图模型

private void RandomiseLines()
{
    var rnd = new Random();

    Values = new ObservableCollection<double>();

    for (int i = 0; i < 3; i++)
    {
        Values.Add(rnd.Next(1, 300));
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-25
    • 1970-01-01
    • 2019-11-14
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多