У меня есть шаблон для моего ComboBox
. взято из здесь . Допустим, каждый элемент имеет тип Node
.
Все отлично работает, но одна вещь поражает меня. Когда я нажимаю между ComboBoxItem
(эта область, я думаю, однопиксельная линия), текст ComboBox меняется на TypeName элементов (с пространством имен).
Я переопределил ToString () метод класса Node
, но CallStack показывает, что программа приходит к нему с [External code]
.
Что я должен сделать, чтобы ComboBox.Text
показал мое строковое свойство вместо TypeName ComboBoxItem
?
Если я пропущу некоторые детали, просто укажите, что есть.
Edit:
Код взят из гиперссылки здесь выше, с некоторыми изменениями.
Использование:
<vm:ComboCheckBox Grid.Column="1" ItemsSource="{Binding Path=Months}"
DefaultText="Select months"/>
Месяцы - это ObservableNodeCollection.
Шаблон [Я не размещаю здесь ресурсы. они такие же, как и по ссылке]:
<ComboBox ItemsSource="{Binding ElementName=UserControl, Path=ItemsSource}"
DataContext="{Binding ElementName=UserControl, Path=DataContext}"
Text="{Binding Path=Text, Mode=OneWay, ElementName=UserControl, UpdateSourceTrigger=PropertyChanged}"
Focusable="False"
IsEditable="False"
Loaded="CheckableCombo_Loaded"
x:Name="CheckableCombo"
SnapsToDevicePixels="True"
OverridesDefaultStyle="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True"
IsSynchronizedWithCurrentItem="True"
MinWidth="120"
MinHeight="20"
>
<ComboBox.ItemTemplate>
<HierarchicalDataTemplate>
<CheckBox Margin="0" IsChecked="{Binding Path=IsSelected}"
Command="{Binding Path=CheckBoxStateChanged, ElementName=UserControl}" CommandParameter="{Binding}"
Content="{Binding Path=Title}" />
</HierarchicalDataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.Template>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton
Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<ContentPresenter
x:Name="Presenter"
IsHitTestVisible="False"
Margin="3,3,23,3"
VerticalAlignment="Center"
HorizontalAlignment="Left">
<ContentPresenter.Content>
<TextBlock TextTrimming="CharacterEllipsis"
Text="{Binding Path=Text,Mode=OneWay,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ComboBox}}" />
</ContentPresenter.Content>
</ContentPresenter>
<TextBox x:Name="EditableTextBox"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="3,3,23,3"
Focusable="True"
Background="Transparent"
Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
ShowGridLines="True"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border Focusable="False"
x:Name="DropDownBorder"
Background="{StaticResource WindowBackgroundBrush}"
BorderThickness="1"
BorderBrush="{StaticResource SolidBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True" DataContext="{Binding}">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle" KeyboardNavigation.ControlTabNavigation="Cycle" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="Presenter" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ComboBox.Template>
</ComboBox>
CodeBehind:
/// <summary>
/// Interaction logic for ComboCheckBox.xaml
/// </summary>
public partial class ComboCheckBox : UserControl
{
public ObservableNodeCollection ItemsSource
{
get
{
return (ObservableNodeCollection)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
SetText();
}
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(ObservableNodeCollection), typeof(ComboCheckBox), new UIPropertyMetadata(null));
/// <summary>
/// Gets or sets the text displayed in the ComboBox
/// </summary>
public string Text
{
get
{
return(string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ComboCheckBox), new UIPropertyMetadata(string.Empty));
/// <summary>
/// Gets or sets the text displayed in the ComboBox if there are no selected items
/// </summary>
public string DefaultText
{
get
{
return(string)GetValue(DefaultTextProperty);
}
set
{
SetValue(DefaultTextProperty, value);
SetText();
}
}
public static readonly DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(ComboCheckBox), new UIPropertyMetadata(string.Empty));
public ComboCheckBox()
{
InitializeComponent();
this.SetText();
}
public ICommand CheckBoxStateChanged
{
get
{
return new Helpers.DelegateCommand<Node>((Node parameter) =>
{
if (parameter.IsSelectAllNode)
{
bool? isSelected = this.ItemsSource[0].IsSelected;
ItemsSource.ToList().ForEach(item => item.IsSelected = isSelected);
}
else
{
if (this.ItemsSource[0].IsSelectAllNode)
{
bool isAllTrue = true, isAllFalse = true;
for (int i = 1; i < this.ItemsSource.Count; i++)
{
isAllTrue = isAllTrue && this.ItemsSource[i].IsSelected.Value;
isAllFalse = isAllFalse && !this.ItemsSource[i].IsSelected.Value;
}
if (isAllTrue)
this.ItemsSource[0].IsSelected = true;
else if (isAllFalse)
this.ItemsSource[0].IsSelected = false;
else
this.ItemsSource[0].IsSelected = null;
}
}
this.SetText();
});
}
}
private void SetText()
{
string answer = String.Empty;
if (ItemsSource != null)
answer = ItemsSource.ToString();
if (String.IsNullOrWhiteSpace(answer))
answer = this.DefaultText;
this.Text = answer;
}
private void CheckableCombo_Loaded(object sender, RoutedEventArgs e)
{
this.SetText();
}
}
Класс узла:
public class Node : ObservableObject
{
public Node(string title, string header = "", bool isSelectAllNode = false, bool? isSelected = false)
{
this.Title = title;
if (String.IsNullOrEmpty(header))
this.Header = title;
else
this.Header = header;
this.IsSelectAllNode = isSelectAllNode;
this.IsSelected = isSelected;
}
public string Header { get; set; }
public string Title { get; set; }
private bool? isSelected;
private const string IsSelectedPropertyName = "IsSelected";
public bool? IsSelected
{
get
{
return this.isSelected;
}
set
{
this.isSelected = value;
this.OnPropertyChanged(IsSelectedPropertyName);
}
}
public bool IsSelectAllNode { get; set; }
public override string ToString()
{
return "123";//if miss it, the typeName will return.
}
}
ObservableNodeCollection:
public class ObservableNodeCollection : ObservableCollection<Node>
{
public ObservableNodeCollection()
{
}
public ObservableNodeCollection(List<Node> list)
: base(list)
{
}
public ObservableNodeCollection(IEnumerable<Node> collection)
: base(collection)
{
}
public override string ToString()
{
string answer = String.Empty;
if (this.Items != null)
{
StringBuilder outString = new StringBuilder();
foreach (Node node in this.Items)
if (node.IsSelected == true && !node.IsSelectAllNode)
{
outString.Append(node.Header);
outString.Append(", ");
}
answer = outString.ToString().TrimEnd(new char[] { ',', ' ' });
}
return answer;
}
}
РЕДАКТИРОВАТЬ 2:
Внутри конструктора ViewModel главного окна существует этот код
int i;
//Initialize months for combobox
this.Months = new ObservableNodeCollection(new List<Node>() { new Node("SelectAll", isSelectAllNode:true)});
for (i=0; i < DateTimeFormatInfo.CurrentInfo.MonthNames.Length; i++)
{
if (!String.IsNullOrEmpty(DateTimeFormatInfo.CurrentInfo.MonthNames[i]))
this.Months.Add(
new Node
(
DateTimeFormatInfo.CurrentInfo.MonthNames[i],
DateTimeFormatInfo.CurrentInfo.AbbreviatedMonthNames[i]
));
}
Итак, this.Months - это ObservableNodeCollection, у которого 1-й элемент - это SelectAll, а остальные 12 элементов - месяцы.