识别由触发事件中的模板创建的复选框

时间:2015-01-13 10:05:06

标签: c# wpf xaml checkbox event-handling

我已经创建了一个可展开的复选框列表,如此。

<Expander x:Name=...>
  <ListBox ItemsSource="{x:Static local:MainWindow.AllTypes}">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <CheckBox Content="{Binding Name}"
                  Checked="ToggleButton_OnToggled"
                  Unchecked="ToggleButton_OnToggled"/>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</Expander>

我也有一个带有下面签名的方法。

private void FilterStuffOut(String condition)
{
  CollectionViewSource source 
    = new CollectionViewSource { Source = dataGrid.ItemsSource };
  ICollectionView view = source.View;
  view.Filter = element => BringItOut(element, condition);
  dataGrid.ItemsSource = view;
}

我不确定(并且在发件人 eventArgs 中没有给我任何内容的智能感知),如何知道哪个复选框是闪亮的。我应该在下面的方法中找到它?

private void ToggleButton_OnToggled(
  Object sender, RoutedEventArgs eventArgs) { ... }

2 个答案:

答案 0 :(得分:2)

您通常会像下面所示编写它,明确地不使用as运算符,而是转换为所需的类型。这是因为您希望这些类型和任何其他类型都会导致运行时错误,即InvalidCastException

private void ToggleButton_OnToggled(object sender, RoutedEventArgs eventArgs)
{
    var element = (FrameworkElement)sender;
    var myType = (MyType)element.DataContext;

    // do something with myType.MyValue
}

如果您需要更多派生类型的属性,例如ToggleButton.IsChecked,您将使用该类型而不是FrameworkElement。

答案 1 :(得分:1)

按照承诺。

我倾向于使用电影作为我的例子,所以请原谅我的习惯。我不确定你的用户界面看起来是什么样的,或者你在这里想要达到的目标,但我认为我理解了这个概念。

如果您不熟悉MVVM设计模式,我建议您完成this教程。

我们走了。

这些是我的模特:

//This is a base class which handles our notify property changed stuff which will update the UI
//when properties change.
public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

上面的类是所有模型的基类,有时在视图模型需要时查看模型。它非常有用,我建议您在所有MVVM应用程序中实现类似的功能。

public class Filter : NotifyPropertyChangedBase
{
    public event EventHandler OnEnabledChanged;

    public string Genre { get; set; }

    private bool _IsEnabled;

    public bool IsEnabled
    {
        get { return _IsEnabled; }
        set 
        { 
            _IsEnabled = value;
            OnPropertyChanged();

            if (OnEnabledChanged != null)
                OnEnabledChanged(this, new EventArgs());
        }
    }

    public Filter(string genre)
    {
        this.Genre = genre;
    }
}

public class Movie
{
    //We don't need to implement INotifyPropertyChanged here
    //because these values will never change.
    public string Name { get; set; }
    public string Genre { get; set; }
}

上述模型代表电影,以及电影类型的过滤器。所有型号都没有&#34;做&#34;任何事情,他们只是代表数据。

这是ViewModel:

public class MovieViewModel : NotifyPropertyChangedBase
{
    private ObservableCollection<Movie> _FilteredMovies;

    public ObservableCollection<Movie> FilteredMovies
    {
        get { return _FilteredMovies; }
        set 
        {
            _FilteredMovies = value;

            //Need to implement INotifyPropertyChanged here because 
            //I am instantiating a new observable collection in the enabled changed
            //method. This will refresh the binding on the DataGrid.
            OnPropertyChanged();
        }
    }

    public ObservableCollection<Movie> Movies { get; set; }
    public ObservableCollection<Filter> Filters { get; set; }

    public MovieViewModel()
    {
        this.Movies = new ObservableCollection<Movie>();
        this.Filters = new ObservableCollection<Filter>();

        #region Sample Data

        this.Movies.Add(new Movie()
            {
                Name = "Movie Action",
                Genre = "Action"
            });

        this.Movies.Add(new Movie()
        {
            Name = "Movie Romance",
            Genre = "Romance"
        });

        this.Movies.Add(new Movie()
        {
            Name = "Movie Comedy",
            Genre = "Comedy"
        });

        this.Filters.Add(new Filter("Action"));
        this.Filters.Add(new Filter("Romance"));
        this.Filters.Add(new Filter("Comedy"));

        foreach (Filter filter in this.Filters)
            filter.OnEnabledChanged += filter_OnEnabledChanged;

        #endregion
    }

    void filter_OnEnabledChanged(object sender, EventArgs e)
    {
        var filteredMovies = (from m in this.Movies
                                join f in this.Filters on m.Genre equals f.Genre
                                where f.IsEnabled
                                select m).ToList();

        this.FilteredMovies = new ObservableCollection<Movie>(filteredMovies);
    }
}

它有一系列电影和一系列过滤器。选中复选框后,将调用OnEnabledChanged方法并将FilteredMovies属性设置为所选过滤器的属性。这反过来将调用notify属性更改的代码并更新UI。

以下是用户界面:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ViewModels="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <ViewModels:MovieViewModel/>
</Window.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Expander>
        <ItemsControl ItemsSource="{Binding Filters}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsEnabled}"
                              Content="{Binding Genre}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Expander>

    <DataGrid Grid.Row="1"
              ItemsSource="{Binding FilteredMovies}"/>
</Grid>

与您的实现类似,有一个DataGrid绑定到ViewModel中的FilteredMovies属性,Filters列表表示为CheckBox对象列表。

就像我之前提到的那样,我并不确定你想要实现什么,但我认为这是你想要做的事情。