【问题标题】:Binding source doesn't change when setting the binding from code behind file从代码隐藏文件设置绑定时,绑定源不会更改
【发布时间】:2018-02-23 13:53:55
【问题描述】:

所以我有这个程序,我主要使用x:Bind 进行所有绑定,但我有一个控制页面,我需要在其中生成大量Slider 才能操作我存储在@987654326 中的数据@

我真的需要从我的代码中生成这些滑块,因为我需要大约 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&lt;T&gt;,具体取决于我需要它们的类型。

滑块源是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 的东西,它有点有用。因此,如果有问题,请告诉我,我将其删除。

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

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

【问题讨论】:

  • “我需要大约 100 个”听起来应该在 ItemsControl 中。
  • 它不仅仅是滑块。首先像这样测试它更容易。根据传入的数据,我可能还需要一个 TextBox 或只需要一个 ToggleSwitch。我对 ItemsControl 不是很熟悉,但在那种情况下或者只有当我只有一种特定类型的元素时它是否可用?
  • 如果没有将 ItemsControl 的 ItemTemplate 设置为固定的 DataTemplate(如答案所示),则可以针对不同的项目类型显示不同的 DataTemplate。源项目集合可能被声明为ObservableCollection&lt;object&gt;。然后只需将具有 DataType 属性的 DataTemplates 声明为资源。从这里开始阅读:Data Templateing Overview

标签: c# xaml uwp win-universal-app


【解决方案1】:

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

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

如果数据可能在多个布局之间变化,你可以实现一个DataTemplateSelector类,覆盖SelectTemplateCore(object item, DependencyObject container)(这个方法具体来说,还有另一个同名但不同数量的参数没有被调用)和决定每个项目的正确模板。您可以使用x:Key 创建多个DataTemplates 作为资源,然后从DataTemplateSelector 中引用它们。有关示例,请参阅此 blog post,有关详细信息,请参阅 documentation

【讨论】:

  • 这绝对比我的方法更好:DI 在绑定工作时遇到了一些问题,我仍然需要实现DataTemplateSelector,但到目前为止,我对它的改进程度印象深刻:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-30
  • 2018-08-15
  • 1970-01-01
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多