【问题标题】:Detecting leaving usercontrol检测离开用户控件
【发布时间】:2016-09-13 08:01:49
【问题描述】:

我有一个列表框,里面有我的菜单项。

 <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"   

【问题讨论】:

  • 尝试过 LostFocus 事件?
  • 不,我对 WPF 有点陌生,我会尝试一下并回复您。

标签: c# wpf mvvm architecture user-controls


【解决方案1】:

更新 #1

处理“从视图导航”有不止一个可能有用的建议,这里有几个简单的例子:

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

这里是 IsHitTest 可见性的示例(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),您可以使用它的事件来知道导航已启动(也就是您将移动到另一个控件),例如FragmentNavigation。李>

此外,您应该在 ViewModel 上实现 IsDirty。以下是一些如何做到这一点的示例:

  1. MVVM - implementing 'IsDirty' functionality to a ModelView in order to save data
  2. Almost-automatic INotifyPropertyChanged, automatic IsDirty, and automatic ChangeTracking

这是 IsDirty 实现的一些代码示例(all credit to this guy)

/// <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
}

如果您需要更多示例或代码,请告诉我。

【讨论】:

  • 谢谢,我已经可以在我的视图模型上检测到 isdirty,但是在用户从用户控件导航之前我无法对其进行测试。此外,仅链接 anwsers 也不是最佳的
  • @DaImTo 感谢您的评论,非常感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
  • 2015-01-10
  • 2013-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多