【问题标题】:Failing to add different items in combobox on dynamic radiobutton click无法在动态单选按钮单击时在组合框中添加不同的项目
【发布时间】:2012-10-23 21:25:59
【问题描述】:

我正在我的 wpf 应用程序中处理单选按钮和组合框。虽然我是一名 C++ 开发人员,但我最近转向了 C#。我的应用程序处理上述组件的动态生成。基本上我在我的应用程序中创建了 4 个动态单选按钮,单击每个按钮时,我应该将不同的项目添加到我的组合框中。代码如下:

XAML:

<ItemsControl ItemsSource="{Binding Children}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical" >
                        <RadioButton Content="{Binding RadioBase}"  Margin="0,10,0,0"  IsChecked="{Binding BaseCheck}" GroupName="SlotGroup"  Height="15" Width="80" HorizontalAlignment="Center" VerticalAlignment="Center"/>                            
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

<ComboBox Visibility="{Binding IsRegisterItemsVisible}" ItemsSource="{Binding RegComboList}" SelectedItem="{Binding SelectedRegComboList, Mode=TwoWay}" SelectedIndex="0" />

FPGARadioWidgetViewModel 类:

public ObservableCollection<FPGAViewModel> Children { get; set; }

    public FPGARadioWidgetViewModel()
    {
        Children = new ObservableCollection<FPGAViewModel>();
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0x0", ID = 0 });
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0x40", ID = 1 });
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0x80", ID = 2 });
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0xc0", ID = 3 });            
    }

FPGAViewModel 类:

private bool sBaseCheck;
    public bool BaseCheck
    {
        get { return this.sBaseCheck; }
        set
        {
            this.sBaseCheck = value;                
            AddComboItems();
            this.OnPropertyChanged("BaseCheck");
        }
    }    

private ObservableCollection<string> _RegComboList;
    public ObservableCollection<string> RegComboList
    {
        get { return _RegComboList; }
        set
        {
            _RegComboList = value;
            OnPropertyChanged("RegComboList");
        }
    }        

private void AddComboItems()
    {
        int baseRegister = 0x40 * ID;
        ObservableCollection<string> combo = new ObservableCollection<string>();            

        for (int i = 0; i < 0x40; i++)
        {
            int reg = (i * 8) + baseRegister;
            combo[i] = "0x" + reg.ToString("X");
        }

        RegComboList = new ObservableCollection<String>(combo);
        OnPropertyChanged("RegComboList");
    }


private bool isRegisterItemsVisible = false;
    public bool IsRegisterItemsVisible
    {
        get { return isRegisterItemsVisible; }
        set
        {
            isRegisterItemsVisible = value;
            OnPropertyChanged("IsRegisterItemsVisible");                
            OnPropertyChanged("RegComboList");
        }
    }

如果您注意到,在单击特定单选按钮时,它应该根据 ID 在组合框中添加具有不同值的项目。必须确保在单击任何单选按钮时,仅应添加该项目,并且应清除组合框的先前内容。我正在尝试使用上面的代码做同样的事情,但是当我调试时,组合框中似乎没有出现任何内容。

请帮忙:)

【问题讨论】:

  • 你说它们在不同的视图模型中?你是如何分配 DataContext 的?他们俩的观点是一样的吗? -- 如果是这样,您似乎没有正确绑定 ItemsSource。
  • @AlexCurtis:DataContext 绑定到 FPGARadioWidgetViewModel 类。有 2 类 FPGARadioWidgetViewModel 和其他 FPGAViewModel :)
  • 它如何知道要绑定哪些子 RegComboList?您可能需要在 FPGARadioWidgetViewModel 中有一个 SelectedFPGAViewModel.RegComboList 绑定
  • @AlexCurtis:我很困惑。请您详细说明一下。一个示例代码会很棒:)

标签: c# wpf xaml dynamic mvvm


【解决方案1】:

这是因为组合框已绑定到不同的字符串引用。每次单选单击都会更改项目并返回对列表的 new 引用。尝试通过删除其中的现有项目来重用当前 RegComboList,然后添加新项目。如果更新组合框失败,请以两种方式绑定到 RegComboList。

编辑:这是一个工作示例 .Net 4.5,不用担心概念是一样的。

这里的组合框最初加载了 5 个单词。然后每次用户单击按钮时,都会将一组新单词放入列表中,从而更改组合框。 请注意为收集完成的清除操作。

图片是在初始“Lorem Ipsum”加载之后...

<Window x:Class="WPFCombo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50*" />
            <RowDefinition Height="50*" />
            <RowDefinition Height="172*" />
        </Grid.RowDefinitions>
        <Button Content="Button"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Width="75"
                Click="Button_Click_1" />
        <ComboBox HorizontalAlignment="Center"
                  Grid.Row="1"
                  ItemsSource="{Binding RegComboList}"
                  VerticalAlignment="Center"
                  Width="120" />
    </Grid>
</Window>

后面的代码

public partial class MainWindow : Window,  INotifyPropertyChanged
{
    private const string cLorem = @"Lorem ipsum dolor sit amet consectetur adipiscing elit Maecenas
                                   et lacinia nisl Aenean nec aliquet risus Phasellus dui purus 
                                   sollicitudin nec cursus vitae cursus id purus Nam quis risus 
                                   velit Sed aliquam tellus in odio pulvinar tincidunt Sed bibendum mi";



    private int Skip { get; set; }
    private ObservableCollection<string> _RegComboList;
    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<string> RegComboList
    {
        get { return _RegComboList; }
        set
        {
            _RegComboList = value;
            OnPropertyChanged();
        }
    }


    public MainWindow()
    {
        InitializeComponent();
        RegComboList = new ObservableCollection<string>();
        GenerateWords(5);

        DataContext = this;
    }

    private void GenerateWords(int toTake)
    {
        RegComboList.Clear();

        Regex.Split(cLorem, @"\s+").Skip(Skip)
             .Take(toTake)
             .ToList()
             .ForEach(word => RegComboList.Add( word ));

        Skip += toTake;

    }

    protected virtual void OnPropertyChanged( [CallerMemberName] string propertyName = "" )
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler( this, new PropertyChangedEventArgs( propertyName ) );
        }
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        GenerateWords(new Random().Next(1, 10));
    } 
}

【讨论】:

  • 好吧,我尝试设置双向模式,但在这里抛出错误:combo[i] = "0x" + reg.ToString("X"); as Index was out of range. Must be non-negative and less than the size of the collection.
  • @StevenWilson 在尝试动态加载之前,您为什么不尝试加载带有虚拟文本的框...这样您就可以确定您的问题实际出在哪里...
【解决方案2】:

我会将您的 ComboBox 的 ItemsSource 与选定的 RadioButton 相关联。从您现有的模型中,我会让每个FPGAViewModel 都有一个您已经完成的ObservableCollection&lt;string&gt;。然后,正如 Alex Curtis 所说,您将在选定的单选按钮和组合框的 ItemsSource 之间创建一个绑定。

查看this 帖子,通过更改您的 ItemsControl 以使用带有现有 DataTemplate 的 ListBox 可能更容易获得选定的单选按钮。然后,您可以将 IsChecked 属性绑定到 ListBoxItem.IsSelected。

           <ListBox ItemsSource="{Binding Children}" SelectedItem="{Binding YourSelectedItem}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical" >
                            <RadioButton Content="{Binding RadioBase}"  Margin="0,10,0,0"  GroupName="SlotGroup"  Height="15" Width="80" HorizontalAlignment="Center" VerticalAlignment="Center">
                                <RadioButton.IsChecked>
                                    <Binding Path="IsSelected"
                                     RelativeSource="{RelativeSource AncestorType=ListBoxItem}" Mode="TwoWay" />
                                </RadioButton.IsChecked>
                            </RadioButton>                            
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>


<ComboBox Visibility="{Binding YourSelectedItem.IsRegisterItemsVisible}" ItemsSource="{Binding YourSelectedItem.RegComboList}" SelectedItem="{Binding YourSelectedItem.SelectedRegComboList, Mode=TwoWay}" SelectedIndex="0" />

然后在包含 Children 集合的 ViewModel 中,您需要有一个:

    private FPGAViewModel _yourSelectedItem;

    public FPGAViewModel YourSelectedItem
    {
        get { return _yourSelectedItem; }
        set { _yourSelectedItem = value;
        OnPropertyChanged("YourSelectedItem");}
    }

要填充您的项目,我将更改 FPGAViewModel 的构造函数以接受 Base 和 ID 作为参数,以便您可以在构造函数中调用 AddComboItems()

public FPGAViewModel(string radioBase, int id)
{
    RadioBase = radioBase;
    ID = id;
    AddComboItems();
}

现在

Children.Add(new FPGAViewModel() { RadioBase = "Base 0x0", ID = 0 });

应该变成

Children.Add(new FPGAViewModel("Base 0x0", 0));

【讨论】:

  • AddComboItems()是否每次都需要触发?你不能在FPGAViewModel初始化时调用一次吗?
  • 每次单击单选按钮时都会触发它。由于存在 4 个单选按钮,因此每次单击时,都会将不同的项目添加到组合中。
  • 是的,如果您将每个 RegComboList 填充一次,就会发生这种情况。除非您每次选择不同的单选按钮时都需要更改每个 RegComboList 的内容,否则无需重新填充列表。
  • 在 HTML 中,我会使用四个组合框来执行此操作,一次只有一个是可见的,具体取决于选中的单选按钮...我不知道这种方法是否会很好地翻译成 WPF,因为我自己还是 WPF 新手。
  • @nmaait:抛出异常。调用构造函数。当我评论构造函数时,应用程序工作.......
猜你喜欢
  • 2012-09-09
  • 1970-01-01
  • 2012-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多