C#代码, 有点乱,待整理
public class BookComboBoxEdit: ComboBox, INotifyPropertyChanged
{
public BookComboBoxEdit()
: base()
{
DataCollection = new List<BookViewModel>()
{
new BookViewModel(){Name = "C++语言程序设计",Price =39.9,Publisher = "谭浩强"},
new BookViewModel(){Name = "Java深入浅出",Price =39.9,Publisher = "谭浩强"}
};
DataCollectionView = CollectionViewSource.GetDefaultView(DataCollection);
DataCollectionView.Filter = new Predicate<object>(OnFilter);
this.PropertyChanged += SymbolEdit_PropertyChanged;
}
private void SymbolEdit_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals("SelctedInstance"))
{
if (SelctedInstance != null)
{
SelectedBook = SelctedInstance.Name;
Price = SelctedInstance.Price;
App.Current.Dispatcher.Invoke(()=>DataCollectionView.Refresh());
}
}
if (e.PropertyName.Equals("SelectedBook"))
{
if (SelctedInstance != null && !FilterByCondition(SelctedInstance, SelectedBook))
{
SelctedInstance = null;
Price = double.NaN;
}
App.Current.Dispatcher.Invoke(()=>DataCollectionView.Refresh());
}
if (e.PropertyName.Equals("DataCollection"))
{
App.Current.Dispatcher.Invoke(() =>
{
if (DataCollection==null)return;
DataCollectionView = CollectionViewSource.GetDefaultView(DataCollection);
DataCollectionView.Filter += OnFilter;
});
}
}
private bool OnFilter(object mod)
{
//只读不可输入的不需要过滤
if (IsTextEditable) return true;
var book = mod as BookViewModel;
if (book != null && !string.IsNullOrWhiteSpace(SelectedBook))
{
return FilterByCondition(book, SelectedBook);
}
else
return true;
}
private bool FilterByCondition(BookViewModel vm, string condition)
{
return vm != null && !string.IsNullOrWhiteSpace(condition)&&(vm.Name.Trim().Contains(condition) || vm.Name.Equals(condition, StringComparison.CurrentCultureIgnoreCase));
}
private ICollectionView dataCollectionView;
private ObservableCollection<BookViewModel> dataCollection;
public ICollectionView DataCollectionView
{
get { return dataCollectionView; }
set
{
if (dataCollectionView != value)
{
dataCollectionView = value;
OnPropertyChanged("DataCollectionView");
};
}
}
public static readonly DependencyProperty DataCollectionProperty = DependencyProperty.Register("DataCollection",
typeof(IEnumerable<BookViewModel>), typeof(BookComboBoxEdit), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(TotalPropertyChanged)));
public IEnumerable<BookViewModel> DataCollection
{
get { return (IEnumerable<BookViewModel>)GetValue(DataCollectionProperty); }
set
{
SetValue(DataCollectionProperty,value);
}
}
public static readonly DependencyProperty IsTextEditableProperty = DependencyProperty.Register("IsTextEditable",
typeof(bool), typeof(BookComboBoxEdit), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(TotalPropertyChanged)));
public bool IsTextEditable
{
get { return (bool)GetValue(IsTextEditableProperty); }
set { SetValue(IsTextEditableProperty, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public static readonly DependencyProperty SelectedBookProperty = DependencyProperty.Register("SelectedBook",
typeof(string), typeof(BookComboBoxEdit), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(TotalPropertyChanged)));
public string SelectedBook
{
get { return (string)GetValue(SelectedBookProperty); }
set { SetValue(SelectedBookProperty, value); }
}
private static void TotalPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((BookComboBoxEdit)d).OnPropertyChanged(e.Property.Name);
}
public static readonly DependencyProperty SelctedInstancekProperty = DependencyProperty.Register("SelctedInstance",
typeof(BookViewModel), typeof(BookComboBoxEdit), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(TotalPropertyChanged)));
public BookViewModel SelctedInstance
{
get { return (BookViewModel)GetValue(SelctedInstancekProperty); }
set
{
SetValue(SelctedInstancekProperty,value);
}
}
private double price=double.NaN;
public double Price
{
get { return price; }
set
{
if (price != null)
{
price = value;
OnPropertyChanged("Price");
}
}
}
}
xaml代码
<converter:DoubleNanConverter x:Key="doubleNanConv"/>
<converter:StringToBoolConverter x:Key="stringToBoolCov"/>
<converter:PoupIsOpenMultiConverter x:Key="poupIsOpenMultiConv"/>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="noBorderTextBoxStyle" TargetType="TextBox">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
<Style x:Key="dropDownToggleButtonStyle" TargetType="ToggleButton">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Width" Value="25"/>
<Setter Property="Height" Value="25"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<!--<ContentPresenter />-->
<Grid>
<Image x:Name="img" Source="../Images/DropDown.png">
<Image.RenderTransform>
<RotateTransform x:Name="RotateTransfer" CenterX="12.5" CenterY="12.5" Angle="0"/>
</Image.RenderTransform>
</Image>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#808080"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#F5F5F5"></Setter>
</Trigger>
<!--<EventTrigger RoutedEvent="ToggleButton.Checked">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation By="180" Duration="0:0:.1"
Storyboard.TargetName="RotateTransfer"
Storyboard.TargetProperty="Angle" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ToggleButton.Unchecked">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation By="-180" Duration="0:0:.1"
Storyboard.TargetName="RotateTransfer"
Storyboard.TargetProperty="Angle" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>-->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:BookComboBoxEdit}">
<Setter Property="Height" Value="Auto"/>
<Setter Property="Width" Value="200"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:BookComboBoxEdit}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderThickness="0.5" BorderBrush="#808080">
<Grid VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBox IsReadOnly="{Binding IsTextEditable,RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource noBorderTextBoxStyle}" Grid.Column="0" Width="Auto" MinWidth="150" x:Name="txt_Input"
Text="{Binding SelectedBook,RelativeSource={RelativeSource TemplatedParent},UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Grid.Column="1" Margin="8,0,0,0" HorizontalAlignment="Right" Text="{Binding Price,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource doubleNanConv}}"/>
<ToggleButton Grid.Column="2" x:Name="btnToggle" HorizontalAlignment="Right" Margin="8,0,0,0" Style="{StaticResource dropDownToggleButtonStyle}">
</ToggleButton>
</Grid>
</Border>
<!--数据匹配列表-->
<Popup Grid.Row="1" x:Name="dataList" StaysOpen="True" PlacementTarget="{Binding ElementName=txt_Input}" AllowsTransparency="True"
IsOpen="{Binding ElementName=btnToggle,Path=IsChecked,Mode=OneWay}">
<!--<Popup.IsOpen>
<MultiBinding Converter="{StaticResource poupIsOpenMultiConv}">
<Binding ElementName="btnToggle" Path="IsChecked"/>
<Binding ElementName="txt_Input" Path="Text"/>
</MultiBinding>
</Popup.IsOpen>-->
<ListView x:Name="_listView" Focusable="True" AllowDrop="True" IsEnabled="True" Width="Auto" Height="Auto"
SelectedItem="{Binding SelctedInstance,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
ItemsSource="{Binding DataCollectionView,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
>
<ListView.View>
<GridView AllowsColumnReorder="True">
<!--<GridViewColumn Header="选择" CellTemplate="{StaticResource checkBoxGridViewColumn}"/>-->
<GridViewColumn Header="书名" Width="Auto" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="价格" Width="Auto" DisplayMemberBinding="{Binding Price}"/>
<GridViewColumn Header="作者" Width="Auto" DisplayMemberBinding="{Binding Publisher}"/>
</GridView>
</ListView.View>
</ListView>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" SourceName="txt_Input" Value="True"/>
<Condition Property="Text" SourceName="txt_Input" Value=""/>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter TargetName="dataList" Property="IsOpen" Value="False"></Setter>
</MultiTrigger.Setters>
</MultiTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=txt_Input,Path=IsFocused}" Value="True"/>
<Condition Binding="{Binding ElementName=txt_Input,Path=Text,Converter={StaticResource stringToBoolCov}}"
Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="dataList" Property="IsOpen" Value="True"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<EventTrigger SourceName="btnToggle" RoutedEvent="LostFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetName="btnToggle"
Storyboard.TargetProperty="IsChecked"
>
<DiscreteBooleanKeyFrame
KeyTime="0:0:0.2"
Value="False"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Converter
public class DoubleNanConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
var d=double.NaN;
double.TryParse(value.ToString(), out d);
return double.IsNaN(d)? string.Empty : d.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
public class StringToBoolConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value != null && !string.IsNullOrWhiteSpace(value.ToString());
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class PoupIsOpenMultiConverter:IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values == null || values.Length < 2)
return false;
var isChecked = false;
var text = values[1];
bool.TryParse(values[0].ToString(), out isChecked);
if (isChecked)
{
return true;
}
else
{
return text!=null&&!string.IsNullOrWhiteSpace(text.ToString());
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}