次の単純な WPF アプリがあります。
<Window x:Class="TabControlOutOfRangeException.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<TabControl ItemsSource="{Binding ItemsSource}"
SelectedIndex="{Binding SelectedIndex, IsAsync=True}" />
</Window>
次の単純なコード ビハインドを使用します。
using System.Collections.Generic;
namespace TabControlOutOfRangeException
{
public partial class MainWindow
{
public List<string> ItemsSource { get; private set; }
public int SelectedIndex { get; set; }
public MainWindow()
{
InitializeComponent();
ItemsSource = new List<string>{"Foo", "Bar", "FooBar"};
DataContext = this;
}
}
}
2 番目のタブ (「バー」) をクリックすると、何も表示されません。任意のタブをもう一度クリックすると、IndexOutOfRangeException が発生します。IsAsync を False に設定すると、TabControl が機能します。
残念ながら、ユーザーに「変更を保存しますか?」と問い合わせる必要があります。彼が現在のタブを離れたときの質問。そこで、set-property 内で SelectedIndex を古い値に戻したいと考えました。明らかにこれは機能しません。私は何を間違っていますか?
アップデート
TabControl を邪悪なハックでサブクラス化したところ、うまくいきました。MainWindow.xaml のコードは次のとおりです。
<Window x:Class="TabControlOutOfRangeException.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:TabControlOutOfRangeException="clr-namespace:TabControlOutOfRangeException" Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControlOutOfRangeException:PreventChangingTabsTabControl
ItemsSource="{Binding ItemsSource}"
SelectedIndex="{Binding SelectedIndex}"
CanChangeTab="{Binding CanChangeTab}" Margin="0,0,0,51" />
<CheckBox Content="CanChangeTab" IsChecked="{Binding CanChangeTab}" Margin="0,287,0,0" />
</Grid>
</Window>
ここで MainWindow.xaml.cs:
using System.Collections.Generic;
using System.ComponentModel;
namespace TabControlOutOfRangeException
{
public partial class MainWindow : INotifyPropertyChanged
{
public int SelectedIndex { get; set; }
public List<string> ItemsSource { get; private set; }
public MainWindow()
{
InitializeComponent();
ItemsSource = new List<string> { "Foo", "Bar", "FooBar" };
DataContext = this;
}
private bool _canChangeTab;
public bool CanChangeTab
{
get { return _canChangeTab; }
set
{
_canChangeTab = value;
OnPropertyChanged("CanChangeTab");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(property));
}
}
}
最後に、サブクラス化された TabControl:
using System;
using System.Windows;
using System.Windows.Controls;
namespace TabControlOutOfRangeException
{
public class PreventChangingTabsTabControl : TabControl
{
private int _previousTab;
public PreventChangingTabsTabControl()
{
SelectionChanged += (s, e) =>
{
if (!CanChangeTab)
{
e.Handled = true;
SelectedIndex = _previousTab;
}
else
_previousTab = SelectedIndex;
};
}
public static readonly DependencyProperty CanChangeTabProperty = DependencyProperty.Register(
"CanChangeTab",
typeof(Boolean),
typeof(PreventChangingTabsTabControl)
);
public bool CanChangeTab
{
get { return (bool)GetValue(CanChangeTabProperty); }
set { SetValue(CanChangeTabProperty, value); }
}
}
}