使用Viewmodel WPF将自定义控件添加到堆栈面板

时间:2012-01-10 10:00:53

标签: wpf mvvm

我有一个自定义控件,在按钮上点击时需要多次添加。这必须从MVVM WPF模式中获得。我在这里粘贴了我的代码。如果你们能帮忙解决这个问题会很棒。

请帮帮我

<Window x:Class="DOCS_APP_ELEMENT.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:usercontrol="clr-namespace:DOCS_APP_ELEMENT"
    xmlns:viewModel="clr-namespace:DOCS_APP_ELEMENT.ViewModels"
    Title="MainWindow" Height="350" Width="400">
<Grid Margin="10" Name="myGrid">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
    </Grid.RowDefinitions>
    <Border CornerRadius="5" BorderBrush="SteelBlue" BorderThickness="2" Grid.Row="0">
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <Label Content="Type:" Margin="20,0,4,0"></Label>
                <ComboBox Name="cmbQuestionType" Width="300" Style="{Binding ComboBoxStyle}" Margin="0,5,0,5" IsEnabled="False">                   </ComboBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="0,5,0,5">
                <Label Content="Question:" Margin="0,0,4,0"></Label>
                <TextBox Name="txtQuestion" Width="300" Height="50" Margin="0,2,0,0" AcceptsReturn="True"></TextBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="0,5,0,5" >
                <Label Content="Answer:" Margin="7,0,4,0"></Label>
                <TextBox Name="txtAnswer" Style="{StaticResource TextboxStyle}" Margin="0,2,0,0"></TextBox>
            </StackPanel>
        </StackPanel>
    </Border>
    <Border CornerRadius="5" BorderBrush="SteelBlue" BorderThickness="2" Grid.Row="1" Margin="0,10,0,0" >
        <ScrollViewer VerticalScrollBarVisibility="Auto" Height="100">
        <StackPanel Name="myCustom" Orientation="Vertical" >
                **<!--<ADD CUSTOM CONTROl HERE>-->**
            </StackPanel>
        </ScrollViewer>
    </Border>
    <Border CornerRadius="5" BorderBrush="SteelBlue" BorderThickness="2" Grid.Row="2" Margin="0,10,0,0">
        <Border.DataContext>
            <viewModel:ViewElements/>                    
        </Border.DataContext>
        <Button  Name="btnAdd" Content="Add" DataContext="{Binding }" Command="{Binding Path=AddInstace}"></Button>
    </Border>
</Grid>

2 个答案:

答案 0 :(得分:6)

我会按照以下方式进行:

在ViewModel中有ObservableCollection<CustomClass>。 CustomClass的表示形式是带有上述标记的DataTemplate。

这是一个完整的工作示例:

  <Grid>
    <Grid.DataContext>
      <local:MyViewModel></local:MyViewModel>
    </Grid.DataContext>
      <StackPanel>
      <ScrollViewer VerticalScrollBarVisibility="Auto" Height="200">
        <ItemsControl ItemsSource="{Binding CustomControls}">
          <ItemsControl.ItemTemplate>
            <DataTemplate>
              <Border Background="Green"> 
                <StackPanel>
                  <TextBlock Text="I am a Custom Control"></TextBlock>
                  <TextBlock Text="{Binding DisplayValue}"></TextBlock>
                </StackPanel>
              </Border>
            </DataTemplate>
          </ItemsControl.ItemTemplate>
          <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
              <StackPanel/>
            </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>
          </ItemsControl>
      </ScrollViewer>
      <Button Width="200" Height="50" Command="{Binding AddControlCommand}">Add Control</Button>
      <Button Width="200" Height="50" Command="{Binding RemoveControlCommand}">Remove Control</Button>
    </StackPanel>
  </Grid>

<强>视图模型:

  public abstract class ViewModel : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }

  public class RelayCommand : ICommand
  {
    ... look that up yourself if you don't have a derived command class yet in your project... 
  }

  public class MyViewModel : ViewModel
  {
    public ICommand AddControlCommand
    {
      get
      {
        return new RelayCommand(x=>this.AddControl());
      }
    }

    public ICommand RemoveControlCommand
    {
      get
      {
        return new RelayCommand(x => this.RemoveControl());
      }
    }

    private void AddControl()
    {
      CustomControls.Add(new CustomControl() {DisplayValue = "newControl"});
    }

    private void RemoveControl()
    {
      if (CustomControls.Count > 0)
      {
        CustomControls.Remove(CustomControls.Last());
      }
    }

    private ObservableCollection<CustomControl> _customControls;

    public ObservableCollection<CustomControl> CustomControls
    {
      get
      {
        if (_customControls == null)
        {
        _customControls = new ObservableCollection<CustomControl>()
                 {
                   new CustomControl() {DisplayValue = "Control1"},
                   new CustomControl() {DisplayValue = "Control2"},
                   new CustomControl() {DisplayValue = "Control3"}
                 };
        }
        return _customControls;
      }
    }
  }

  public class CustomControl : ViewModel
  {
    public string DisplayValue { get; set; }
  }

答案 1 :(得分:4)

要使用MVVM模式,您需要一个ViewModel,它包含绑定到自定义控件的数据对象列表。这个控件可以由ItemsControl生成。由于我不知道你的数据,我可以给你一个一般的例子。

MainWindow.xaml(查看)

<ItemsControl ItemsSource="{Binding DataList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <!-- instead of the TextBlock you would use your control -->
            <TextBlock Text="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

MainWindow.xaml.cs(查看代码隐藏)

public MainWindow()
{
    DataContext = new MainWindowViewModel();
    InitializeComponent();
}

MainWindowViewModel.cs(ViewModel)

public class MainWindowViewModel
{
    public ObservableCollection<string> DataList { get; set; }

    public MainWindowViewModel()
    {
        DataList = new ObservableCollection<string>
                    {
                        "Data 1",
                        "Data 2",
                        "Data 3"
                    };
    }
}

Text属性的Binding没有路径,因为DataContext这里是DataList的字符串对象。如果使用复杂对象,则必须使用对象属性的路径(例如Text={Binding Path=myProperty}