WPFでは、ComboBoxから「ヌル」値を(マウスで)選択することは不可能のようです。 編集明確にするために、これは.NET 3.5 SP1です。
これが私が何を意味するかを示すためのコードです。まず、C#宣言:
public class Foo
{
public Bar Bar { get; set; }
}
public class Bar
{
public string Name { get; set; }
}
次に、私のWindow1 XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<ComboBox x:Name="bars"
DisplayMemberPath="Name"
Height="21"
SelectedItem="{Binding Bar}"
/>
</StackPanel>
</Window>
そして最後に、私のWindow1クラス:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
bars.ItemsSource = new ObservableCollection<Bar>
{
null,
new Bar { Name = "Hello" },
new Bar { Name = "World" }
};
this.DataContext = new Foo();
}
}
私と一緒に?項目がBarインスタンスのリストにバインドされているComboBoxがあり、その1つがnullです。ウィンドウをFooのインスタンスにバインドし、ComboBoxがそのBarプロパティの値を表示しています。
このアプリを実行すると、Foo.Barはデフォルトでnullであるため、ComboBoxは空のディスプレイで始まります。それはいいです。マウスを使用してComboBoxをドロップダウンし、「Hello」アイテムを選択すると、それも機能します。しかし、リストの上部にある空のアイテムを再度選択しようとすると、ComboBoxが閉じて、以前の値の「Hello」に戻ります。
矢印キーでnull値を選択すると期待どおりに機能し、プログラムで設定することもできます。機能しないのは、マウスで選択することだけです。
簡単な回避策は、nullを表すBarのインスタンスを作成し、それをIValueConverterで実行することですが、WPFのComboBoxでマウスを使用してnullを選択しても機能しない理由を誰かが説明できますか?
ヌル「アイテム」はキーボードでまったく選択されていません-むしろ、前のアイテムは選択されておらず、後続のアイテムは選択されていません(選択可能です)。これは、「選択」した後、キーボードを使用してnull項目を選択すると、その後、以前に選択した項目( "Hello")を再選択できなくなります-マウスを使用する場合を除きます。
つまり、ComboBoxでnullアイテムを選択または選択解除することはできません。そうしていると思われる場合は、以前のアイテムまたは新しいアイテムの選択を解除または選択しています。
これはおそらく、ComboBoxの項目に背景を追加することで最もよくわかります。 「Hello」を選択すると、ComboBoxの背景が色付きになりますが、キーボードで選択を解除すると、背景色が消えます。マウスでリストをドロップすると、nullアイテムは実際には背景色を持つため、これはnullアイテムではないことがわかります。
元の質問のXAMLから変更された次のXAMLは、項目の背後にLightBlue背景を配置して、この動作を確認できるようにします。
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<ComboBox x:Name="bars" Height="21" SelectedItem="{Binding Bar}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid Background="LightBlue" Width="200" Height="20">
<TextBlock Text="{Binding Name}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Window>
さらに検証が必要な場合は、ComboBoxのSelectionChangedイベントを処理して、「nullアイテムを選択」すると、実際にSelectionChangedEventArgsにAddedItemsの空の配列が表示され、「マウスで「Hello」を選択してnullアイテムの選択を解除する」ことがわかります。 RemovedItemsの空の配列を提供します。
さて、私は最近nullComboBoxの値で同じ問題に遭遇しました。 2つのコンバーターを使用して解決しました。
ItemsSourceプロパティの場合:コレクション内のnull値を、コンバーターのパラメーター内で渡された任意の値に置き換えます。
class EnumerableNullReplaceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var collection = (IEnumerable)value;
return
collection
.Cast<object>()
.Select(x => x ?? parameter)
.ToArray();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
SelectedValueプロパティの場合:これは同じことを行いますが、単一の値と2つの方法で行います。
class NullReplaceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value ?? parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.Equals(parameter) ? null : value;
}
}
使用例:
<ComboBox
ItemsSource="{Binding MyValues, Converter={StaticResource EnumerableNullReplaceConverter}, ConverterParameter='(Empty)'}"
SelectedValue="{Binding SelectedMyValue, Converter={StaticResource NullReplaceConverter}, ConverterParameter='(Empty)'}"
/>
結果:
注:ObservableCollectionにバインドすると、変更通知が失われます。また、コレクションに複数のnull値を含める必要はありません。
私はこの答えがあなたが求めたものではないことを知っていますが(それがマウスで機能しない理由の説明)、私はその前提に欠陥があると思います:
プログラマーおよびユーザー(.NETではない)としての私の観点からは、null値を選択することは悪いことです。 「null」は、選択したものではなく、値がないことを前提としています。
何かを明示的に選択しない機能が必要な場合は、あなたが言及した回避策(値として「-」、「n.a。」、または「none」)、またはそれ以上をお勧めします
私は1日を費やして、comboboxでnull値を選択するというこの問題の解決策を見つけました。最後に、ええと、最終的にこのURLに書かれた記事で解決策を見つけました。
public class ComboBoxEmptyItemConverter : IValueConverter
{
/// <summary>
/// this object is the empty item in the combobox. A dynamic object that
/// returns null for all property request.
/// </summary>
private class EmptyItem : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// just set the result to null and return true
result = null;
return true;
}
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// assume that the value at least inherits from IEnumerable
// otherwise we cannot use it.
IEnumerable container = value as IEnumerable;
if (container != null)
{
// everything inherits from object, so we can safely create a generic IEnumerable
IEnumerable<object> genericContainer = container.OfType<object>();
// create an array with a single EmptyItem object that serves to show en empty line
IEnumerable<object> emptyItem = new object[] { new EmptyItem() };
// use Linq to concatenate the two enumerable
return emptyItem.Concat(genericContainer);
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<ComboBox ItemsSource="{Binding TestObjectCollection, Converter={StaticResource ComboBoxEmptyItemConverter}}"
SelectedValue="{Binding SelectedID}"
SelectedValuePath="ID"
DisplayMemberPath="Name" />
これはあなたの答えに完全に対処しないかもしれませんが、うまくいけばそれは正しい方向へのヒットです:
- NET 3.5 SP1には、いくつかのデータバインディングと編集の改善が含まれています
WPF。これらには以下が含まれます:- バインドされた値の簡単なフォーマットを可能にする{{Binding}}式内のStringFormatサポート
- ItemsControlから派生したコントロール内の新しい交互の行のサポート。これにより、行に交互のプロパティを設定しやすくなります(例:交互の背景色)
- 編集可能なコントロールでのnull値の処理と変換のサポートの向上バインドされたアイテム全体に検証ルールを適用するアイテムレベルの検証
- 複数選択および一括編集シナリオを処理するためのMultiSelectorサポート
- IEditableCollectionViewのサポートにより、データコントロールをデータソースにインターフェースし、アイテムをトランザクション的に編集/追加/削除できるようにします。
- IEnumerableデータソースにバインドするときのパフォーマンスの向上
私があなたの時間を無駄にして、これが近くさえなかったなら申し訳ありません。しかし、問題は以下から継承されると思います:
しかし今、.Net 3.5のSP1はこの問題に対処しているはずです。
ComboBoxは、項目がどれほど単純であっても、項目を表示するためにDataTemplateを必要とします。 DataTemplateは次のように機能します。インスタンスから値を取得します。[パス]。
bar1.Car.Color
したがって、値を取得できません
null.Car.Color
Null参照例外がスローされます。そのため、nullインスタンスは表示されません。ただし、この場合は例外がないため、Color(参照型の場合)はnullにすることができます。
同じような問題があり、次のようにコレクションプロパティに値プロパティを追加するなど、いくつかの回避策を実行しました。
public class Bar
{
public string Name { get; set; }
public Bar Value
{
get { return String.IsNullOrEmpty(Name) ? null : this; } // you can define here your criteria for being null
}
}
次に、nullの代わりに項目を追加するときに、同じオブジェクトを使用します。
comboBox1.ItemsSource= new ObservableCollection<Bar>
{
new Bar(),
new Bar { Name = "Hello" },
new Bar { Name = "World" }
};
そして、selecteditemの代わりに、私はそれをselectedvalueにバインドします:
<ComboBox Height="23" Margin="25,40,133,0" DisplayMemberPath="Name"
SelectedValuePath="Value"
SelectedValue="{Binding Bar}"
Name="comboBox1" VerticalAlignment="Top" />
私はそれが完全な解決策ではなく、私が使用する1つの回避策だけを知っています
Binding.FallbackValueをお試しください
推測に過ぎませんが、それは妥当なように思えます。
コンボボックスが "ListCollectionView"(インスタンスとしてlcv)をアイテムコレクションとして使用していると想定します。あなたがプログラマーなら、あなたはどうするつもりですか?
キーボードとマウスの両方に対応します。
キーボード入力を受け取ったら、
lcv.MoveCurrentToNext();
または
lcv.MoveCurrentToPrevious();
だから、キーボードがうまく機能することを確認してください。
次に、マウス入力の応答に取り組んでいます。そして、問題が発生します。
アイテムの「MouseClick」イベントを聞きたいのですが。しかし、おそらく、私のアイテムは生成されず、単なるプレースホルダーです。したがって、ユーザーがこのプレースホルダーをクリックしても、何も表示されません。
イベントに成功したら、次は何をしますか。呼び出します
lcv.MoveCurrentTo(selectedItem);
nullになる "selectedItem"は、ここでは許容できるパラメータではありません。
とにかく、それはただの推測です。デバッグはできますが、デバッグする時間がありません。修正すべき欠陥がたくさんあります。幸運を。 :)