检测离开usercontrol

时间:2016-05-17 09:36:30

标签: c# wpf mvvm architecture user-controls

我有一个包含菜单项的ListBox。

 <ListBox x:Name="ListBoxMenu"  SelectionChanged="ListBoxMenu_SelectionChanged"             
                 Grid.Column="0" Margin="0" Padding="0" Grid.Row="1" Width="{StaticResource LeftMenuWidth}"                 
                 ItemsSource="{Binding MenuItems}"
                 Background="{StaticResource ListBoxColor}"
                 BorderThickness="0"
                 SelectedIndex="0" VerticalAlignment="Stretch" >
 <ListBox.ItemTemplate>
                <DataTemplate>
                    <DockPanel>
                        <Image Source="{Binding MenuImage}" Height="20" Width="20" DockPanel.Dock="Left" Margin="5" />
                        <TextBlock Text="{Binding MenuName}" FontSize="{StaticResource MenuFontSize}" FontWeight="Bold" DockPanel.Dock="Left" Width="Auto" VerticalAlignment="Center" HorizontalAlignment="Left"/>
                    </DockPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

切断了代码,希望它仍然可以制作。

然后我有一个加载每个用户控件的控件模板。

<ContentControl Content="{Binding ElementName=ListBoxMenu, Path=SelectedItem}" Grid.Column="1" Grid.Row="1"/>

问题:

我的问题是,我想测试用户何时离开用户控件,如果他们进行了任何更改以要求他们保存更改。我已经有NotifyPropertyChange工作,所以这不是问题所在。我需要弄清楚如何查看用户何时离开控件/页面。

我尝试了什么

正如您所看到的,我已将selectionchanged添加到列表框中,但在技术上确实有效,但由于用户控件在视觉上发生了变化,因此提示用户保存所有更改。我想在他们离开用户控件之前提示他们。

SelectionChanged="ListBoxMenu_SelectionChanged"   

1 个答案:

答案 0 :(得分:0)

更新#1

有一个以上可能有用的建议来处理&#34;从视图导航&#34;,这里有几个简单的例子:

  1. 为了检查您的控件是否处于活动状态(我的意思是向用户显示),当没有使用任何导航控制器时,我认为您可以使用控件的IsVisibleChanged事件来指示控件&#39 ; s IsVisible(true / false)状态。如果您想要在控件部分可见时启动IsDirty逻辑,您可以使用@Evk家伙建议(使用LostFocus),测试控件边界上的IsHitTestVisible并根据测试结果(隐藏控件的程度)你可以开始(或不开始)你想要的逻辑。
  2. 以下是IsHitTest visibilty(from this link

    的示例
        /// <summary>
        /// helps to indicate the partial IsVisible state
        /// </summary>
        /// <param name="element">elemnt under the test</param>
        /// <param name="container">parent window or control</param>
        /// <returns></returns>
        private bool IsUserVisible(FrameworkElement element, FrameworkElement container)
        {
            if (!element.IsVisible)
                return false;
    
            Rect bounds = element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
            Rect rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
            return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight);
        }
    
    1. 如果您有导航支持控件(类似于Frame),您可以使用其事件来了解导航已启动(也就是您要移动到另一个控件),例如{{3} }。
    2. 此外,您应该在ViewModel上实现IsDirty。以下是如何执行此操作的几个示例:

      1. FragmentNavigation
      2. MVVM - implementing 'IsDirty' functionality to a ModelView in order to save data
      3. 以下是IsDirty实施的一些代码示例(Almost-automatic INotifyPropertyChanged, automatic IsDirty, and automatic ChangeTracking

        /// <summary>
        /// Provides a base class for objects that support property change notification 
        /// and querying for changes and resetting of the changed status.
        /// </summary>
        public abstract class ViewModelBase : IChangeTracking, INotifyPropertyChanged
        {
            //========================================================
            //  Constructors
            //========================================================
            #region ViewModelBase()
            /// <summary>
            /// Initializes a new instance of the <see cref="ViewModelBase"/> class.
            /// </summary>
            protected ViewModelBase()
            {
                this.PropertyChanged += new PropertyChangedEventHandler(OnNotifiedOfPropertyChanged);
            }
            #endregion
        
            //========================================================
            //  Private Methods
            //========================================================
            #region OnNotifiedOfPropertyChanged(object sender, PropertyChangedEventArgs e)
            /// <summary>
            /// Handles the <see cref="INotifyPropertyChanged.PropertyChanged"/> event for this object.
            /// </summary>
            /// <param name="sender">The source of the event.</param>
            /// <param name="e">A <see cref="PropertyChangedEventArgs"/> that contains the event data.</param>
            private void OnNotifiedOfPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (e != null && !String.Equals(e.PropertyName, "IsChanged", StringComparison.Ordinal))
                {
                    this.IsChanged = true;
                }
            }
            #endregion
        
            //========================================================
            //  IChangeTracking Implementation
            //========================================================
            #region IsChanged
            /// <summary>
            /// Gets the object's changed status.
            /// </summary>
            /// <value>
            /// <see langword="true"/> if the object’s content has changed since the last call to <see cref="AcceptChanges()"/>; otherwise, <see langword="false"/>. 
            /// The initial value is <see langword="false"/>.
            /// </value>
            public bool IsChanged
            {
                get
                {
                    lock (_notifyingObjectIsChangedSyncRoot)
                    {
                        return _notifyingObjectIsChanged;
                    }
                }
        
                protected set
                {
                    lock (_notifyingObjectIsChangedSyncRoot)
                    {
                        if (!Boolean.Equals(_notifyingObjectIsChanged, value))
                        {
                            _notifyingObjectIsChanged = value;
        
                            this.OnPropertyChanged("IsChanged");
                        }
                    }
                }
            }
            private bool _notifyingObjectIsChanged;
            private readonly object _notifyingObjectIsChangedSyncRoot = new Object();
            #endregion
        
            #region AcceptChanges()
            /// <summary>
            /// Resets the object’s state to unchanged by accepting the modifications.
            /// </summary>
            public void AcceptChanges()
            {
                this.IsChanged = false;
            }
            #endregion
        
            //========================================================
            //  INotifyPropertyChanged Implementation
            //========================================================
            #region PropertyChanged
            /// <summary>
            /// Occurs when a property value changes.
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
            #endregion
        
            #region OnPropertyChanged(PropertyChangedEventArgs e)
            /// <summary>
            /// Raises the <see cref="INotifyPropertyChanged.PropertyChanged"/> event.
            /// </summary>
            /// <param name="e">A <see cref="PropertyChangedEventArgs"/> that provides data for the event.</param>
            protected void OnPropertyChanged(PropertyChangedEventArgs e)
            {
                var handler = this.PropertyChanged;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
            #endregion
        
            #region OnPropertyChanged(string propertyName)
            /// <summary>
            /// Raises the <see cref="INotifyPropertyChanged.PropertyChanged"/> event for the specified <paramref name="propertyName"/>.
            /// </summary>
            /// <param name="propertyName">The <see cref="MemberInfo.Name"/> of the property whose value has changed.</param>
            protected void OnPropertyChanged(string propertyName)
            {
                this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
            }
            #endregion
        
            #region OnPropertyChanged(params string[] propertyNames)
            /// <summary>
            /// Raises the <see cref="INotifyPropertyChanged.PropertyChanged"/> event for the specified <paramref name="propertyNames"/>.
            /// </summary>
            /// <param name="propertyNames">An <see cref="Array"/> of <see cref="String"/> objects that contains the names of the properties whose values have changed.</param>
            /// <exception cref="ArgumentNullException">The <paramref name="propertyNames"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
            protected void OnPropertyChanged(params string[] propertyNames)
            {
                if (propertyNames == null)
                {
                    throw new ArgumentNullException("propertyNames");
                }
        
                foreach (var propertyName in propertyNames)
                {
                    this.OnPropertyChanged(propertyName);
                }
            }
            #endregion
        }
        

        如果您想要更多示例或代码,请与我们联系。