今日仕事で嵌ったので調べてみた。
Silverlight の Popup で表示している ComboBox をクリックしたら、フリーズしました。
MSDN Popup クラス のサンプルに ComboBox 追加して試しても発生したので間違いないと思う。
以下ミニマムコード
Page.xaml
<UserControl x:Class="SilverlightApplication3.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:Name="LayoutRoot" Background="Yellow"> <Button Content="test" Click="Button_Click" Width="80" Height="30" /> </Grid> </UserControl>Page.cs
using System.Windows; using System.Windows.Controls; namespace SilverlightApplication3 { public partial class Page : UserControl { public Page() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { SilverlightControl1 s = new SilverlightControl1(); s.ShowDialog(); } } }SilverlightControl1.xaml
<UserControl x:Class="SilverlightApplication3.SilverlightControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="200" Height="100"> <Grid x:Name="LayoutRoot" Background="Aqua"> <StackPanel Orientation="Vertical"> <TextBlock Text="test"/> <ComboBox> <ComboBoxItem Content="Test1" IsSelected="True"/> <ComboBoxItem Content="Test2"/> <ComboBoxItem Content="Test3"/> </ComboBox> <Button Content="Close" Click="Button_Click"/> </StackPanel> </Grid> </UserControl>SilverlightControl1.cs
using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; namespace SilverlightApplication3 { public partial class SilverlightControl1 : UserControl { Popup _popup = new Popup(); public SilverlightControl1() { InitializeComponent(); this._popup.Child = this; } public void ShowDialog() { if (this._popup.IsOpen) { return; } this._popup.IsOpen = true; } public void CloseDialog() { this._popup.IsOpen = false; } private void Button_Click(object sender, RoutedEventArgs e) { this.CloseDialog(); } } }
調べたら、こんなサイトが出てきた。MSDN Silverlight Dev Center(相変わらず英語が読めない)
Popup を VisualTree に追加したら、回避出来るらしい。(そう読みとれた。間違ってるかも)
VisualTree ってなんだ?良く分からないので、「Silverlight VisualTree」で調べてみてもあんまり出てこない。
「Silverlight ビジュアル ツリー」 で MSDN Silverlight オブジェクト ツリー が引っ掛かった。
どうも、表示される物(コントロール)の階層構造?みたいなのらしい(間違ってたら、指摘して下さい)
とりあえず、親画面の LayoutRoot に Popup を 追加してたら、回避出来た。
以下修正後ソース
Page.xaml は変更なし
Page.csusing System.Windows; using System.Windows.Controls; namespace SilverlightApplication3 { public partial class Page : UserControl { public Page() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { SilverlightControl1 s = new SilverlightControl1(this.LayoutRoot); // Popup を追加するため、LayoutRoot(Grid)を渡す。 s.ShowDialog(); } } }SilverlightControl1.xaml
<UserControl x:Class="SilverlightApplication3.SilverlightControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="200" Height="100"> <Grid Background="Aqua"> <!-- 複数追加する事を考えて、Name を指定しない。 --> <StackPanel Orientation="Vertical"> <TextBlock Text="test"/> <ComboBox> <ComboBoxItem Content="Test1" IsSelected="True"/> <ComboBoxItem Content="Test2"/> <ComboBoxItem Content="Test3"/> </ComboBox> <Button Content="Close" Click="Button_Click"/> </StackPanel> </Grid> </UserControl>SiverlightControl1.cs
using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; namespace SilverlightApplication3 { public partial class SilverlightControl1 : UserControl { Popup _popup = new Popup(); Panel _parent; // Popup を追加するコントロール(ここでは、Page.LayoutRoot が渡ってくる) public SilverlightControl1(Panel parent) { if (parent == null) { throw new ArgumentNullException("parent"); } InitializeComponent(); this._popup.Child = this; this._parent = parent; } public void ShowDialog() { if (this._popup.IsOpen) { return; } this._parent.Children.Add(_popup); // 表示する前に、Popup を 追加する。 this._popup.IsOpen = true; } public void CloseDialog() { if (!this._popup.IsOpen) { return; } this._popup.IsOpen = false; this._parent.Children.Remove(this._popup); // 閉じたら、Popup を 削除する。 } private void Button_Click(object sender, RoutedEventArgs e) { this.CloseDialog(); } } }
これで、回避出来たよ。
注意点!!
- Popup で表示するコントロールに名前を付けていると、親で表示しているコントロールと名前が被った場合エラーになる。
(多分、ツリーには同じ名前がいたらダメ?)
- Popup は、モーダル では無いので続けて呼び出される可能性がある。