如何动态生成必须放置在动态生成的Groupbox中的ToggleButtons

时间:2012-10-18 10:51:46

标签: c# .net wpf mvvm toggle

我是C ++开发人员,最近搬到了C#。我正在开发WPF应用程序,它处理动态生成的groupbox。必须动态生成各个组框中存在的诸如RadioButton,togglebutton等UI组件。

目前我有2个xaml文件CodecView.xamlCodecWidgetView.xaml,这两个xaml文件都是一个单独的viewmodel类。那么这个动态的一代很有意思,但对我来说肯定是一个棘手的情况。让我向您展示我动态生成一组groupbox的代码。

CodecView.xaml:

<UserControl.Resources>
    <DataTemplate x:Key="CWDataTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Description}" Margin="5,5,0,0"/>
            <local:CodecWidgetView Margin="5,10,5,5"/>
        </StackPanel>
    </DataTemplate>
</UserControl.Resources>

<Grid Grid.Row="0" Style="{DynamicResource styleBackground}">          
        <Grid Name="NumberofCodecs" >
            <ItemsControl ItemTemplate="{StaticResource CWDataTemplate}" ItemsSource="{Binding CodecWidgets}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Grid>            
 </Grid>

CodecWidgetView.xaml:

<Grid>
    <GroupBox Height="Auto" HorizontalAlignment="Stretch" Margin="5,5,5,5" Name="groupBox1" VerticalAlignment="Stretch" Width="Auto">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>

            <Grid Grid.Row="0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <ToggleButton Name="MasterBox" Content="Master" Command="{Binding MasterCommand}" IsChecked="{Binding MasterCheck}" Grid.Column="1" Height="25" Width="50" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0" />
                <ComboBox Grid.Column="2" ItemsSource="{Binding ModesList}" SelectedItem="{Binding SelectedModesList, Mode=OneWayToSource}" SelectedIndex="2" Height="23" HorizontalAlignment="Center" Margin="0,0,0,0" Name="comboBox2" VerticalAlignment="Center" Width="80" />
                <ComboBox Grid.Column="0" ItemsSource="{Binding FrequencyList}" SelectedItem="{Binding SelectedFrequencyList, Mode=OneWayToSource}" SelectedIndex="0" Height="23" HorizontalAlignment="Center" Margin="0,0,0,0" Name="comboBox1" VerticalAlignment="Center" Width="80" />
            </Grid>

            <Grid Grid.Row="1">
                //Here I want to dynamically generate 4 radio buttons
            </Grid>

            <Grid Grid.Row="2">
                <Label Name="BitDelay" Content="Bit Delay" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,205,0" Height="25" Width="55" />
                <Slider Height="23" HorizontalAlignment="Center" Value="{Binding BitDelayValue, Mode=TwoWay}" Minimum="0.0" Maximum="255.0" TickFrequency="1.0" Margin="95,0,0,0" Name="bitdelayslider" VerticalAlignment="Center" Width="160" />
                <TextBox Name="BitDelayValue" IsReadOnly="True" Text="{Binding ElementName=bitdelayslider,Path=Value, StringFormat=0.0}" Width="40" Height="20" Margin="0,0,110,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Grid>

            <Grid Grid.Row="3">
                <Label Name="DBGain" Content="DB Gain" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,205,0" Height="25" Width="55" />
                <TextBox Name="DBGainValue" IsReadOnly="True" Text="{Binding ElementName=dbgainslider,Path=Value, StringFormat=0.0}" Width="40" Height="20" Margin="0,0,110,0" HorizontalAlignment="Center" VerticalAlignment="Center" />
                <Slider Height="23" HorizontalAlignment="Center" Value="{Binding DBGainValue, Mode=TwoWay}" Minimum="0.0" Maximum="59.5" TickFrequency="0.5" Margin="95,0,0,0" Name="dbgainslider" VerticalAlignment="Center" Width="160" />
            </Grid>
        </Grid>
    </GroupBox>
</Grid>

CodecViewModel.cs:

public ObservableCollection<CodecWidgetViewModel> CodecWidgets { get; set; }

    public CodecViewModel()
    {
        CodecWidgets = new ObservableCollection<CodecWidgetViewModel>();
        CodecWidgets.Add(new CodecWidgetViewModel { Description = "Location 8  - Dig Mic A" });
        CodecWidgets.Add(new CodecWidgetViewModel { Description = "Location 9  - Dig Mic B" });
        CodecWidgets.Add(new CodecWidgetViewModel { Description = "Location 10  - PCM A 3P3V" });
        CodecWidgets.Add(new CodecWidgetViewModel { Description = "Location 11  - PCM B 3P3V" });
    }

CodecWidgetViewModel.cs:

private string _description;
    public string Description
    {
        get
        { 
            return _description; 
        }

        set
        {
            _description = value;
            OnPropertyChanged("Description");
        }
    }

这在启动时给了我4个组框。现在这里是要求:

  1. 看一下CodecWidgetView.xaml,你会发现我添加了组合框,滑块等,但在Grid.Row=2我想动态生成4个切换按钮,内容为:16 Bit, 20 Bit, 24 Bit and 32 Bit
  2. 一旦发生这种情况,此按钮上必须只有一个点击事件,用于设置切换状态并执行一些语句。
  3. 这就是我在C ++中的表现:

    //In Constructor
    for(int jj = 0; jj < 4; jj++)
    {
        m_codecBitLengthButton[jj] = new ToggleButton(bitLengthes[jj]); //Here bitlength consists of 16Bit, 20Bit, 24Bit and 32Bit
        m_codecBitLengthButton[jj]->setRadioGroupId(55); // make a custom group ID
        addAndMakeVisible(m_codecBitLengthButton[jj]);
        m_codecBitLengthButton[jj]->addButtonListener(this);
        m_codecBitLengthButton[jj]->setToggleState(false, false);
    }
    // check which button should be pressed
        cmd = (0x9400 | (m_slot & 0xFF));
    m_msp430->ReadInternalCommand(cmd, 1, readBuf); //This returns some value in readBuf
    m_bitLength = readBuf[0];
    m_codecBitLengthButton[readBuf[0]]->setToggleState(true, false); //Togglestate set to true on startup based on readBuf[0]
    
    
    //Gets called when any of the toggle button is clicked
    while(jj < 4)
    {
        if(button == m_codecBitLengthButton[jj])
        {
            // add code for bit length support
            cmd = ((CODEC_LENGTH_CMD & 0x7F00) | (m_slot & 0xFF));
            sendBuf[numBytes++] = jj; // this should represent the proper number of bits
            m_bitLength = jj;
            break;
        }
        jj++;
    }
    

    我如何在C#中实现同样的目标? :)

1 个答案:

答案 0 :(得分:1)

您可以使用命令执行此操作:

<强> CodecWidgetView.xaml:

<Grid Grid.Row="1">
     <Grid.ColumnDefinitions>
           <ColumnDefinition />
           <ColumnDefinition />
           <ColumnDefinition />
           <ColumnDefinition />
     </Grid.ColumnDefinitions>
     <ToggleButton Grid.Column="0" Content="16Bit" Command="{Binding Path=ToogleButtonCommand}" CommandParameter="16"/>
     <ToggleButton Grid.Column="1" Content="20Bit" Command="{Binding Path=ToogleButtonCommand}" CommandParameter="20"/>
     <ToggleButton Grid.Column="2" Content="24Bit" Command="{Binding Path=ToogleButtonCommand}" CommandParameter="24"/>
     <ToggleButton Grid.Column="3" Content="32Bit" Command="{Binding Path=ToogleButtonCommand}" CommandParameter="32"/>
</Grid>

这将非常简单并以mvvm的方式。

好处是您可以指定CommandParameter将使用哪个参数。在Sample i中对它进行了硬编码,但它也可以绑定。

<强> CodecWidgetViewModel.cs:

    RelayCommand _toogleButtonCommand;
    public ICommand ToogleButtonCommand
    {
        get
        {
            if (_toogleButtonCommand == null)
            {
                _toogleButtonCommand = new RelayCommand(this.DoSomethingExecute,
                    this.DoSomethingCanExecute);
            }
            return _toogleButtonCommand;
        }
    }

    public void DoSomethingExecute(object param)
    {
       int result = Convert.ToInt32(param);

        if (result == 16)
        {
            //To this and so on for example
        }
    }

希望这有帮助。

修改 要随时定义IsChecked哪个按钮,请在ViewModel中绑定ToogleButtons IsChecked属性,并为ToogleButton的值绑定属性。

private bool _isCheckedToogle1;
public bool IsCheckedToogle1
{
    get { return _isCheckedToogle1; }
    set
    {
        _isCheckedToogle1 = value;
        OnPropertyChanged("IsCheckedToogle1");
    }
}

private int _toogleButton1Value = 16;
public int ToogleButton1Value
{
   get { return _toogleButton1Value; }
   set
   {
      _toogleButton1Value = value;
      OnPropertyChanged("ToogleButton1Value");
   }
}

XAML:

<ToggleButton Grid.Column="0" x:Name="toogleButton1" Content="16Bit" Command="{Binding Path=ToogleButtonCommand}" IsChecked="{Binding Path=IsCheckedToogle1}" >
    <ToggleButton.CommandParameter>
        <MultiBinding Converter="{StaticResource Converter}">
             <Binding Path="ToggleButton1Value" />
             <Binding />
        </MultiBinding>
    </ToggleButton.CommandParameter>
</ToggleButton>

因为它现在是一个MutliBinding,你需要一个转换器和一个新值的类,这是参数:

    public object Convert(object[] values, Type targetType, object parameter,
       System.Globalization.CultureInfo culture)
    {
        ToggleValue val = new ToggleValue();
        val.View = values[1] as CodecWidgetViewModel;
        val.Value = System.Convert.ToInt32(values[0]);
        return val;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
        System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();

    }
}

public class ToggleValue
{
    public int Value { get; set; }
    public CodecWidgetViewModel View { get; set; }
}

你的新CommandLogik

    public void DoSomethingExecute(object param)
    {
        ToggleValue result = param as ToggleValue;

        if (result.Value == 16)
        {
            result.View.IsCheckedToogle1 = true;
            result.View.IsCheckedToogle2 = false;
            result.View.IsCheckedToogle3 = false;
            result.View.IsCheckedToogle4 = false;
        }
    }