我正在尝试为我的应用程序开发一个系统维护屏幕,其中我有几个选项卡,每个选项卡代表不同的维护选项,即维护系统用户等。一旦用户点击edit / new来更改现有记录,我想阻止导航离开当前标签,直到用户点击保存或取消。
经过一些谷歌搜索后,我找到了一个链接http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/,这似乎解决了我的问题,或者我认为。
我已经尝试过这个,但我的事件似乎永远不会发生。以下是我的XAML。
<TabControl Name="tabControl">
<TabItem Header="Users">
<DockPanel>
<GroupBox Header="Existing Users" Name="groupBox1" DockPanel.Dock="Top" Height="50">
<StackPanel Orientation="Horizontal">
<Label Margin="3,3,0,0">User:</Label>
<ComboBox Width="100" Height="21" Margin="3,3,0,0"></ComboBox>
<Button Width="50" Height="21" Margin="3,3,0,0" Name="btnUsersEdit" Click="btnUsersEdit_Click">Edit</Button>
<Button Width="50" Height="21" Margin="3,3,0,0" Name="btnUsersNew" Click="btnUsersNew_Click">New</Button>
</StackPanel>
</GroupBox>
<GroupBox Header="User Information" Name="groupBox2">
<Button Content="Cancel" Height="21" Name="btnCancel" Width="50" Click="btnCancel_Click" />
</GroupBox>
</DockPanel>
</TabItem>
<TabItem Header="User Groups">
</TabItem>
</TabControl>
这是我的代码
public partial class SystemMaintenanceWindow : Window
{
private enum TEditMode { emEdit, emNew, emBrowse }
private TEditMode _EditMode = TEditMode.emBrowse;
private TEditMode EditMode
{
get { return _EditMode; }
set
{
_EditMode = value;
}
}
public SystemMaintenanceWindow()
{
InitializeComponent();
var view = CollectionViewSource.GetDefaultView(tabControl.Items.SourceCollection);
view.CurrentChanging += this.Items_CurrentChanging;
}
void Items_CurrentChanging(object sender, CurrentChangingEventArgs e)
{
if ((e.IsCancelable) && (EditMode != TEditMode.emBrowse))
{
var item = ((ICollectionView)sender).CurrentItem;
e.Cancel = true;
tabControl.SelectedItem = item;
MessageBox.Show("Please Save or Cancel your work first.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void btnUsersNew_Click(object sender, RoutedEventArgs e)
{
EditMode = TEditMode.emNew;
}
private void btnUsersEdit_Click(object sender, RoutedEventArgs e)
{
EditMode = TEditMode.emEdit;
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
EditMode = TEditMode.emBrowse;
}
}
现在道歉,如果我是愚蠢的,但对于我的生活,我无法锻炼,看看为什么当用户在标签之间点击时我的事件不会触发。
感谢您的帮助。
埃姆林
答案 0 :(得分:14)
我想出了一个适合我需求的解决方案。似乎略微倒退,但与其他选项相比,我发现它看起来很漂亮。
基本上我保留当前tabIndex的私有变量和tabControl的“SelectionChanged”事件我正在做一些检查,如果用户不处于浏览模式,则将tabControl.SelectedIndex设置回此值。 / p>
private void tabControl_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (e.OriginalSource == tabControl)
{
if (EditMode == TEditMode.emBrowse)
{
_TabItemIndex = tabControl.SelectedIndex;
}
else if (tabControl.SelectedIndex != _TabItemIndex)
{
e.Handled = true;
tabControl.SelectedIndex = _TabItemIndex;
MessageBox.Show("Please Save or Cancel your work first.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
答案 1 :(得分:8)
我也在努力解决这个问题。只需添加
即可实现IsSynchronizedWithCurrentItem="True"
设置为TabControl。之后就像一个魅力。
答案 2 :(得分:1)
根据这篇文章
这对我有用:
<TabControl>
<TabControl.Resources>
<Style TargetType="TabItem">
<EventSetter Event="PreviewMouseLeftButtonDown"
Handler="OnPreviewMouseLeftButtonDown"/>
</Style>
</TabControl.Resources>
<TabItem Header="Tab1"/>
<TabItem Header="Tab2"/>
</TabControl>
private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.Source is TabItem) //do not handle clicks on TabItem content but on TabItem itself
{
var vm = this.DataContext as MyViewModel;
if (vm != null)
{
if (!vm.CanLeave())
{
e.Handled = true;
}
}
}
}
答案 3 :(得分:0)
Josh正在使用tab.ItemsSource
。您正在使用tab.Items.SourceCollection
。这可能是问题所在。
答案 4 :(得分:0)
或者自己实施......
public delegate void PreviewSelectionChangedEventHandler(object p_oSender, PreviewSelectionChangedEventArgs p_eEventArgs);
public class PreviewSelectionChangedEventArgs
{
internal PreviewSelectionChangedEventArgs(IList p_lAddedItems, IList p_lRemovedItems)
{
this.AddedItems = p_lAddedItems;
this.RemovedItems = p_lRemovedItems;
}
public bool Cancel { get; set; }
public IList AddedItems { get; private set; }
public IList RemovedItems { get; private set; }
}
public class TabControl2: TabControl
{
public event PreviewSelectionChangedEventHandler PreviewSelectionChanged;
private int? m_lLastSelectedIndex;
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
// déterminer si on doit annuler la sélection
PreviewSelectionChangedEventArgs eEventArgs = new PreviewSelectionChangedEventArgs(e.AddedItems, e.RemovedItems);
if (m_lLastSelectedIndex.HasValue)
if (PreviewSelectionChanged != null)
PreviewSelectionChanged(this, eEventArgs);
// annuler (ou pas) la sélection
if (eEventArgs.Cancel)
this.SelectedIndex = m_lLastSelectedIndex.Value;
else
m_lLastSelectedIndex = this.SelectedIndex;
}
}
答案 5 :(得分:0)
我开始掌握XAML,所以希望我不要错过你的观点。我遇到了同样的问题,对我来说效果最好。
在XAML中,我定义了一种用于切换ReadOnly状态的样式
<!-- prevent the tab from being changed while editing or adding a physician -->
<Style BasedOn="{StaticResource {x:Type TabControl}}"
TargetType="{x:Type TabControl}" x:Key="InactivateTabControl">
<!-- <Setter Property="IsEnabled" Value="True" /> -->
<Style.Triggers>
<DataTrigger Binding="{Binding PhysicianTypeTabAreLocked}" Value="False">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding PhysicianTypeTabAreLocked}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
<TabControl Grid.Row="1" Grid.Column="0" Margin="0, 10, 0, 0"
x:Name="PhysicianTypesTabControl"
SelectedIndex="{Binding PhysicianTypeSelectedTabIndex, Mode=TwoWay}"
Style="{StaticResource InactivateTabControl}">
<!-- rest here ....-->
<TabControl/>
在视图模型中,我有一个属性
private EditingState _PhysicianEditingState;
public EditingState PhysicianEditingState
{
get { return _PhysicianEditingState; }
set
{
_PhysicianEditingState = value;
PhysicianTypeTabAreLocked = (PhysicianEditingState != EditingState.NotEditing);
NotifyPropertyChanged("PhysicianTypeTabAreLocked");
}
}
希望这会有所帮助。