C# 当ItemsSource集合中的属性更改时,如何重新绘制ItemsControl ItemsPanel?

C# 当ItemsSource集合中的属性更改时,如何重新绘制ItemsControl ItemsPanel?,c#,wpf,itemscontrol,C#,Wpf,Itemscontrol,我创建了一个自定义的WeightedUniformGrid类,在ItemsControl中用作ItemsPanel。每个网格元素都使用ItemsSource集合中对象的权重属性进行加权 但是当我在视图模型中更改权重属性时,它不会立即显示在视图中。我必须更改窗口的大小,以便使用新值绘制WeightedUniformGrid 如何使ItemsSource集合中的属性更改导致ItemsControl重新绘制?我想也许在WeightedUniformGrid中添加DependencyProperty,

我创建了一个自定义的WeightedUniformGrid类,在ItemsControl中用作ItemsPanel。每个网格元素都使用ItemsSource集合中对象的权重属性进行加权

但是当我在视图模型中更改权重属性时,它不会立即显示在视图中。我必须更改窗口的大小,以便使用新值绘制WeightedUniformGrid

如何使ItemsSource集合中的属性更改导致ItemsControl重新绘制?我想也许在WeightedUniformGrid中添加DependencyProperty,这将影响范围和影响度量。但我不确定我能把它绑在什么东西上

我在这里搜索了很长一段时间,有一些类似的问题(比如一个)。但我还没能使它们中的任何一个适应我的需要

MainWindow.xaml:

<ItemsControl ItemsSource="{Binding Path=ElementGroupCollection}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <local:WeightedUniformGrid Rows="2" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="1"
                    RenderOptions.EdgeMode="Aliased">
                <Viewbox Stretch="Uniform">
                    <TextBlock Text="{Binding Path=Number}" Foreground="Black" FontSize="20" 
                                    HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Viewbox>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

MainWindowVM.cs:

public class MainWindowVM
{
    public MainWindowVM()
    {
        _elementGroupCollection = new ObservableCollection<ElementGroup>()
        {
            new ElementGroup(1, 60),
            new ElementGroup(2, 150),
            new ElementGroup(3, 90),
            new ElementGroup(4, 80),
            new ElementGroup(5, 60),
            new ElementGroup(6, 160)
        };
    }

    private ObservableCollection<ElementGroup> _elementGroupCollection;
    public ObservableCollection<ElementGroup> ElementGroupCollection
    {
        get { return _elementGroupCollection; }
    }
}
公共类MainWindowVM
{
公共MainWindowVM()
{
_elementGroupCollection=新的ObservableCollection()
{
新元素组(1,60),
新元素组(2150),
新元素组(3,90),
新元素组(4,80),
新元素组(5,60),
新元素组(6160)
};
}
私有可观察集合_elementGroupCollection;
公共可观测集合元素GroupCollection
{
获取{return\u elementGroupCollection;}
}
}
ElementGroup.cs:

public class ElementGroup : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public ElementGroup(int number, double? weight)
    {
        Number = number;
        Weight = (weight >= 0) ? weight : null;
    }

    public int Number { get; }

    private double? _weight;
    public double? Weight
    {
        get { return _weight; }
        set { SetNotify(ref _weight, value); }
    }

    public void SetNotify<T>(ref T storage,
                             T value,
                             [CallerMemberName] string propertyName = null)
    {
        storage = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
公共类元素组:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
公共元素组(整数,双倍重量)
{
数字=数字;
权重=(权重>=0)?权重:空;
}
公共整数{get;}
私人双倍重量;
公众双倍体重
{
获取{return\u weight;}
set{SetNotify(ref_weight,value);}
}
公共无效设置通知(参考T存储、,
T值,
[CallerMemberName]字符串propertyName=null)
{
储存=价值;
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
WeightedUniformGrid.cs:

public class WeightedUniformGrid : UniformGrid
{

    protected override Size MeasureOverride(Size constraint)
    {
        var size = base.MeasureOverride(constraint);
        double elementsPerRow = Math.Ceiling((double)Children.Count / Rows);
        double elementHeight = size.Height / Rows;
        double unweightedElementWidth = size.Width / elementsPerRow;
        for (int i = 0; i < Children.Count; ++i)
        {
            var child = (FrameworkElement)Children[i];
            var dc = child.DataContext;
            int rowNumber = (int)Math.Floor(i / elementsPerRow);
            double? weight = dc.GetType().GetProperty("Weight")?.GetValue(dc, null) as double?;
            if (weight == null) { weight = 100; }
            double weightedElementWidth = unweightedElementWidth * (double)weight / 100;
            child.Measure(new Size(weightedElementWidth, elementHeight));
        }
        return size;
    }

    protected override Size ArrangeOverride(Size arrangeSize)
    {
        var size = base.ArrangeOverride(arrangeSize);
        int elementsPerRow = (int)Math.Ceiling((double)Children.Count / Rows);
        double elementHeight = size.Height / Rows;
        double unweightedElementWidth = size.Width / elementsPerRow;
        double[] accumulatedWidthPerRow = new double[Rows];
        for (int i = 0; i < Children.Count; ++i)
        {
            var child = (FrameworkElement)Children[i];
            var dc = child.DataContext;
            int rowNumber = i / elementsPerRow;
            double? weight = dc.GetType().GetProperty("Weight")?.GetValue(dc, null) as double?;
            if (weight == null) { weight = 100; }
            double weightedElementWidth = unweightedElementWidth * (double)weight / 100;
            child.Arrange(new Rect(new Point(accumulatedWidthPerRow[rowNumber], rowNumber * elementHeight),
                                    new Point(accumulatedWidthPerRow[rowNumber] + weightedElementWidth, (rowNumber + 1) * elementHeight)));
            accumulatedWidthPerRow[rowNumber] += weightedElementWidth;
        }
        return size;
    }
}
公共类WeightedUniformGrid:UniformGrid
{
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
变量大小=基本度量超越(约束);
double elementsPerRow=Math.天花((双)Children.Count/行);
双元素高度=大小。高度/行;
双重未加权元素宽度=大小。宽度/元素如箭头所示;
for(int i=0;i
您的WeightedUniformGrid不能直接访问其子元素的DataContext中的Weight属性。此外,这是一种不好的做法,它无法正常工作,因为当视图模型项的权重发生变化时,没有强制布局传递的机制

应该有一个绑定到权重的附加属性。附加属性的
FrameworkPropertyMetadataOptions
将强制布局传递

public class WeightedUniformGrid : UniformGrid
{
    public static readonly DependencyProperty WeightProperty =
        DependencyProperty.RegisterAttached(
            "Weight", typeof(double), typeof(WeightedUniformGrid),
            new FrameworkPropertyMetadata(double.NaN,
                FrameworkPropertyMetadataOptions.AffectsParentMeasure |
                FrameworkPropertyMetadataOptions.AffectsParentArrange));

    public static double GetWeight(UIElement element)
    {
        return (double)element.GetValue(WeightProperty);
    }

    public static void SetWeight(UIElement element, double value)
    {
        element.SetValue(WeightProperty, value);
    }

    protected override Size MeasureOverride(Size constraint)
    {
        var size = base.MeasureOverride(constraint);
        double elementsPerRow = Math.Ceiling((double)Children.Count / Rows);
        double elementHeight = size.Height / Rows;
        double unweightedElementWidth = size.Width / elementsPerRow;
        for (int i = 0; i < Children.Count; ++i)
        {
            var child = Children[i];
            int rowNumber = (int)Math.Floor(i / elementsPerRow);

            // get attached property value
            double weight = GetWeight(child);
            if (double.IsNaN(weight)) { weight = 100; }

            double weightedElementWidth = unweightedElementWidth * weight / 100;
            child.Measure(new Size(weightedElementWidth, elementHeight));
        }
        return size;
    }

    protected override Size ArrangeOverride(Size arrangeSize)
    {
        var size = base.ArrangeOverride(arrangeSize);
        int elementsPerRow = (int)Math.Ceiling((double)Children.Count / Rows);
        double elementHeight = size.Height / Rows;
        double unweightedElementWidth = size.Width / elementsPerRow;
        double[] accumulatedWidthPerRow = new double[Rows];
        for (int i = 0; i < Children.Count; ++i)
        {
            var child = Children[i];
            int rowNumber = i / elementsPerRow;

            // get attached property value
            double weight = GetWeight(child);
            if (double.IsNaN(weight)) { weight = 100; }

            double weightedElementWidth = unweightedElementWidth * (double)weight / 100;
            child.Arrange(new Rect(new Point(accumulatedWidthPerRow[rowNumber], rowNumber * elementHeight),
                                    new Point(accumulatedWidthPerRow[rowNumber] + weightedElementWidth, (rowNumber + 1) * elementHeight)));
            accumulatedWidthPerRow[rowNumber] += weightedElementWidth;
        }
        return size;
    }
}
公共类WeightedUniformGrid:UniformGrid
{
公共静态只读DependencyProperty WeightProperty=
DependencyProperty.RegisterAttached(
“重量”、类型(双)和类型(重量),
新的FrameworkPropertyMetadata(double.NaN,
FrameworkPropertyMetadataOptions.AffectsParentMeasure|
FrameworkPropertyMetadataOptions.AffectsParentArrange));
公共静态双GetWeight(UIElement)
{
return(double)元素.GetValue(WeightProperty);
}
公共静态无效设置重量(UIElement,双值)
{
元素设置值(WeightProperty,value);
}
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
变量大小=基本度量超越(约束);
double elementsPerRow=Math.天花((双)Children.Count/行);
双元素高度=大小。高度/行;
阴沉的
<ItemsControl ItemsSource="{Binding Path=ElementGroupCollection}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <local:WeightedUniformGrid Rows="2" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="local:WeightedUniformGrid.Weight" Value="{Binding Weight}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
    ...
</ItemsControl>