Я не могу быть уверен точно в том, что вы пытаетесь сделать, не глядя на ваш код подробно, но я думаю, что у меня есть смутное представление о вашем сценарии. Я построил для вас пример, иллюстрирующий нечто похожее на это. Вместо того, чтобы создать новый элемент управления, я поместил весь код в один Window
, для простоты демонстрации. Для начала давайте посмотрим на XAML для окна:
<Window x:Class="TestWpfApplication.DataBoundFlags"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpfApplication"
Title="DataBoundFlags" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding AvailableOptions}" Grid.Row="0">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" CommandParameter="{Binding}"
Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=SelectCommand}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Text="{Binding SelectedOptions}" Grid.Row="1"/>
</Grid>
В окне DataContext
установлен собственный код, поэтому я могу связываться со свойствами там. У меня есть несколько свойств - AvailableOptions
это все варианты, которые вы можете выбрать. SelectedOptions
- это параметры, которые пользователь выбрал в данный момент. SelectCommand
- это RelayCommand
, который используется либо для добавления флага в SelectedOptions
, либо для его удаления.
Остальная часть XAML должна быть очень простой. ListBox
привязан ко всем доступным параметрам, и каждый параметр представлен как один CheckBox
. Обратите особое внимание на CommandParameter
, который привязан к самому пункту опции. Теперь давайте посмотрим на код, где происходит волшебство:
[Flags()]
public enum Options
{
Plain = 0,
Ketchup = 1,
Mustard = 2,
Mayo = 4,
HotSauce = 8
}
public partial class DataBoundFlags : Window
{
public static readonly DependencyProperty SelectedOptionsProperty =
DependencyProperty.Register("SelectedOptions", typeof(Options), typeof(DataBoundFlags));
public Options SelectedOptions
{
get { return (Options)GetValue(SelectedOptionsProperty); }
set { SetValue(SelectedOptionsProperty, value); }
}
public List<Options> AvailableOptions
{
get
{
return new List<Options>()
{
Options.Ketchup,
Options.Mustard,
Options.Mayo,
Options.HotSauce
};
}
}
public ICommand SelectCommand
{
get;
private set;
}
/// <summary>
/// If the option is selected, unselect it.
/// Otherwise, select it.
/// </summary>
private void OnSelect(Options option)
{
if ((SelectedOptions & option) == option)
SelectedOptions = SelectedOptions & ~option;
else
SelectedOptions |= option;
}
public DataBoundFlags()
{
SelectCommand = new RelayCommand((o) => OnSelect((Options)o));
InitializeComponent();
}
}
Начиная сверху, у нас есть объявление enum, за которым следует свойство зависимостей SelectedOptions
и свойство AvailableOptions
(которое может быть стандартным свойством CLR, поскольку оно никогда не изменится). Затем у нас есть наша команда и обработчик, который будет выполняться для команды (всякий раз, когда опция отмечена или не отмечена). Сначала обратите внимание, как команда подключена - мы создаем новый RelayCommand
и сообщаем ему, чтобы он запускал OnSelect
, передавая параметр команды. Помните, что это тот же параметр команды, который был связан в XAML - это означает, что текущая опция отмечена или не отмечена. Мы сравниваем эту опцию с SelectedOptions
, используя побитовые операторы. Если опция существует, это означает, что мы ее снимаем, и нам нужно очистить ее, используя побитовое AND. Если он не существует, мы добавляем его в выбранное, используя побитовое ИЛИ.
Когда это происходит, свойство зависимостей SelectedOptions
автоматически обновляется, что обновляет привязку TextBlock
в XAML. Вот окончательный результат:
альтернативный текст http://img706.imageshack.us/img706/7269/databoundflags.png