从代码隐藏文件设置绑定时绑定源不会更改

Binding source doesn't change when setting the binding from code behind file

所以我有这个程序,我主要通过使用 x:Bind 来完成所有绑定,但我有一个控制页面,我需要在其中生成大量 Slider 才能操作数据我存储在 ObservableCollection<T>

我真的需要从我的代码中生成这些滑块,因为我需要大约 100 个滑块,如果手动创建它们会弄乱我的 xmal 文件...

这就是我在代码中创建绑定的方式。当我第一次加载它们时,它们也会工作。但是当我移动滑块时它们不会更改源数据。

private void CreateGrid()
{
    for (var parameterNumberIndex = 1; parameterNumberIndex < 97; parameterNumberIndex++)
    {
        var paraName = new TextBlock()
        {
            Name = $"Parameter{parameterNumberIndex}",
            FontSize = 25,
            VerticalAlignment = VerticalAlignment.Top,
            Margin = new Thickness(0, 0, 0, 10)
        };

        var slider = new Slider()
        {
            Name = $"ValueSlider{parameterNumberIndex}",
            Width = 200,
            VerticalAlignment = VerticalAlignment.Center,
            HorizontalAlignment = HorizontalAlignment.Center
        };

        var value = new TextBox()
        {
            Name = $"ValueBox{parameterNumberIndex}",
            Margin = new Thickness(10, 5, 0, 0),
            FontSize = 20,
            VerticalAlignment = VerticalAlignment.Top
        };

        var row = new RowDefinition { Height = new GridLength(50, GridUnitType.Pixel) };

        SettingsGrid.RowDefinitions.Add(row);

        var nameBinding = new Binding
        {
            Source = ViewModel.BlockCollection.NamesBlock.Names[parameterNumberIndex].NameString,
            Mode = BindingMode.OneWay
        };

        var valueBinding = new Binding()
        {
            Source = ViewModel.BlockCollection.ParameterBlock.Parameters[parameterNumberIndex].ParameterValue,
            Mode = BindingMode.TwoWay
        };

        var minBinding = new Binding()
        {
            Source = ViewModel.BlockCollection.MinMaxBlock.AllValues[parameterNumberIndex].MinValue,
            Mode = BindingMode.OneWay
        };

        var maxBinding = new Binding()
        {
            Source = ViewModel.BlockCollection.MinMaxBlock.AllValues[parameterNumberIndex].MaxValue,
            Mode = BindingMode.OneWay
        };

        var textBinding = new Binding()
        {
            Path = new PropertyPath("Value"),
            Source = slider,
            Mode = BindingMode.TwoWay
        };

        BindingOperations.SetBinding(paraName, TextBlock.TextProperty, nameBinding);
        BindingOperations.SetBinding(slider, Slider.MinimumProperty, minBinding);
        BindingOperations.SetBinding(slider, Slider.MaximumProperty, maxBinding);
        BindingOperations.SetBinding(slider, Slider.ValueProperty, valueBinding);
        BindingOperations.SetBinding(value, TextBox.TextProperty, textBinding);

        SettingsGrid.Children.Add(paraName);
        SettingsGrid.Children.Add(slider);
        SettingsGrid.Children.Add(value);

        Grid.SetColumn(paraName, 0);
        Grid.SetColumn(slider, 1);
        Grid.SetColumn(value, 2);

        Grid.SetRow(paraName, parameterNumberIndex - 1);
        Grid.SetRow(slider, parameterNumberIndex - 1);
        Grid.SetRow(value, parameterNumberIndex - 1);
    }
}

Source = ... 总是 ObservableCollection<T> 取决于我需要它们的类型。

滑块源是 uint 的集合。

BindableBase是我实现的INotifyPropertyChanged

public class ParameterBlock : BindableBase
{
    public ParameterBlock()
    {
        this.Parameters = new ObservableRangeCollection<ParameterBlockValue>();
    }

    public ObservableRangeCollection<ParameterBlockValue> Parameters
    {
        get => _parameters;
        set
        {
            _parameters = value;
            OnPropertyChanged();
        }
    }        

    private ObservableRangeCollection<ParameterBlockValue> _parameters;
}

public class ParameterBlockValue : BindableBase
{
    private uint _parameterValue;

    public uint ParameterValue
    {
        get => _parameterValue;
        set
        {
            _parameterValue = value;
            OnPropertyChanged();
        }
    }

    public ParameterBlockValue(uint parameter)
    {
        this.ParameterValue = parameter;
    }

    public override string ToString()
    {
        return $"{this.ParameterValue} {Environment.NewLine}";
    }
}

这几乎是我或多或少完成这个项目之前需要修复的最后一步,我不想卡在这里:/

不知道是不是wpf标签写错了。但每次我寻找 xaml 参考时,我都会无意中发现 wpf 的东西,它有点用。所以如果有错请告诉我,我会删除它。

再解释一下...在成品中,将取决于我收到的数据来决定是否会有滑块或文本框。

只是我昨天遇到的另一个问题的一个小示例图片:

我看到您在 Grid 中添加控件,手动生成行。虽然这当然可行,但最好使用列表控件并在以下范围内创建项目:

<ItemsControl ItemsSource="{x:Bind Data}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <!-- your Sliders, etc. -->
        </DataTemplate>
    </ItemsControl.ItemTemplate>
<ItemsControl>

如果多个布局之间的数据可能不同,您可以实现 DataTemplateSelector class,覆盖 SelectTemplateCore(object item, DependencyObject container)(具体来说,还有另一个同名但不同数量的未调用的参数)并为每个项目决定正确的模板。您可以使用 x:Key 创建多个 DataTemplates 作为资源,然后从您的 DataTemplateSelector 引用它们。有关详细信息,请参阅此 blog post for an example and documentation